Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
New tool for network isolation: subrosa
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Networking & Security
View previous topic :: View next topic  
Author Message
bjorn-fischer
n00b
n00b


Joined: 13 Nov 2023
Posts: 8
Location: Bielefeld

PostPosted: Thu Jul 25, 2024 3:06 pm    Post subject: New tool for network isolation: subrosa Reply with quote

Hi folks,

every now and then I have the requirement to run an application isolated from the network.
True, I could set up a container each time, bind mount all necessary file systems into the
container and all that. But that's awfully much boiler plate if I just need network separation.

So I came up with the tiny tool subrosa. You can view it on github/bjorn-fischer/subrosa.
subrosa execs() the command given as arguments in a newly set up network name space
with just a loopback device in it:

Code:

[bf@βελλεροφων:~]$ ping -c 3 193.0.0.164
PING 193.0.0.164 (193.0.0.164) 56(84) bytes of data.
64 bytes from 193.0.0.164: icmp_seq=1 ttl=54 time=24.6 ms
64 bytes from 193.0.0.164: icmp_seq=2 ttl=54 time=25.8 ms
64 bytes from 193.0.0.164: icmp_seq=3 ttl=54 time=22.3 ms

--- 193.0.0.164 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 22.312/24.240/25.782/1.442 ms
[bf@βελλεροφων:~]$ subrosa bash
[bf@βελλεροφων:~]$ ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[bf@βελλεροφων:~]$ ping -c 3 193.0.0.164
ping: connect: Network is unreachable
[bf@βελλεροφων:~]$ exit
exit
[bf@βελλεροφων:~]$


So, network isolation is just a subshell away.

Any comments? Just use containers or eBPF? Or is it even dangerous?

Cheers
Björn
Back to top
View user's profile Send private message
Hu
Administrator
Administrator


Joined: 06 Mar 2007
Posts: 22578

PostPosted: Thu Jul 25, 2024 3:38 pm    Post subject: Reply with quote

On principle, I am leery of anything suid-root, even when it is fairly simple.
https://github.com/bjorn-fischer/subrosa/blob/main/subrosa.c#L38:
        fprintf(stderr, "Usage: %s <executable> [args] ...\n", argv[0]);
This (and later output) assumes stderr is valid and writable. Although that is usually true, the caller could have attached descriptor 2 to a read-only source, or even closed it entirely, causing your suid program to open a file as descriptor 2.
https://github.com/bjorn-fischer/subrosa/blob/main/subrosa.c#L52:
    fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
There is no check that socket succeeded. If socket failed, the ioctl will fail with a potentially confusing error message. It would be better to explicitly goto fail if socket fails, so that the errno explaining why socket failed is still available.
https://github.com/bjorn-fischer/subrosa/blob/main/subrosa.c#L58:
    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) goto fail;
fd is never used after this point, but is not closed, and was not opened as O_CLOEXEC, so I think it will leak into the called process. In conjunction with the above concern about descriptor 2 being closed before program start, you could pass this socket into a child process as descriptor 2, which could cause confusing behavior from it.

Although the semantics are a little different, I prefer using bwrap for ad-hoc containers. It uses a user namespace, so it does not need to be installed suid root. That does, unfortunately, break programs that insist on running their own suid program, since being in the user namespace, that suid program will not get a real root uid.
Back to top
View user's profile Send private message
pietinger
Moderator
Moderator


Joined: 17 Oct 2006
Posts: 5036
Location: Bavaria

PostPosted: Thu Jul 25, 2024 4:08 pm    Post subject: Reply with quote

If you often want to test a program that is not allowed to access the network, there is a simple solution (which does not require a container): Create a user and log in with this user + create a “firewall” as I have described here: https://forums.gentoo.org/viewtopic-t-1169318-highlight-.html
_________________
https://wiki.gentoo.org/wiki/User:Pietinger
Back to top
View user's profile Send private message
bjorn-fischer
n00b
n00b


Joined: 13 Nov 2023
Posts: 8
Location: Bielefeld

PostPosted: Fri Jul 26, 2024 7:48 am    Post subject: Reply with quote

Hu wrote:
On principle, I am leery of anything suid-root, even when it is fairly simple.


That is a sensible approach. I use subrosa with capabilities where ever possible.

Hu wrote:
This (and later output) assumes stderr is valid and writable. Although that is usually true, the caller could have attached descriptor 2 to a read-only source, or even closed it entirely, causing your suid program to open a file as descriptor 2.


How does writing to a stream which underlying descriptor is closed lead to opening a file? Should not write attempts result in EBADF?

Hu wrote:
There is no check that socket succeeded. If socket failed, the ioctl will fail with a potentially confusing error message. It would be better to explicitly goto fail if socket fails, so that the errno explaining why socket failed is still available.


Agreed. Already fixed that.

Hu wrote:
fd is never used after this point, but is not closed, and was not opened as O_CLOEXEC, so I think it will leak into the called process. In conjunction with the above concern about descriptor 2 being closed before program start, you could pass this socket into a child process as descriptor 2, which could cause confusing behavior from it.


Yes indeed. How could that have slipped through?

Thank you for your suggestions.
Back to top
View user's profile Send private message
Hu
Administrator
Administrator


Joined: 06 Mar 2007
Posts: 22578

PostPosted: Fri Jul 26, 2024 2:23 pm    Post subject: Reply with quote

bjorn-fischer wrote:
How does writing to a stream which underlying descriptor is closed lead to opening a file? Should not write attempts result in EBADF?
Yes, writing to a closed descriptor will return EBADF. However, since the kernel allocates the lowest free descriptor when opening a new file, if your caller started you with fd 0 and fd 1 open, and fd 2 closed, then your first file-opening call (open, socket, etc.) will return 2. Since stderr is 2 by default, any later attempt to write to stderr will write to fd 2 - which may be the thing your root privileged program opened, not the fd 2 inherited from your caller. I don't see a way to get your program to open a file as fd 2, but if there were such a way, you would then be writing your error messages to that file, which your root privileges let you open, even if your caller's non-root privileges could not open that file. Such a scenario would be a way for an unprivileged caller to cause your setuid-root program to write text into a file that the caller cannot modify directly.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Networking & Security All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum