[GH-ISSUE #472] Can escape jail with mate-terminal #338

Closed
opened 2026-05-05 05:37:22 -06:00 by gitea-mirror · 15 comments
Owner

Originally created by @Fred-Barclay on GitHub (Apr 22, 2016).
Original GitHub issue: https://github.com/netblue30/firejail/issues/472

This is somewhat similar to #471 but works from inside the jail:
I can blacklist a directory, start a terminal (I've tried mate-terminal) from inside the firejail, and then escape the jail completely with that separate terminal. I can even gain root privs via sudo, which is normally impossible inside the jail:

fred@aussie ~ $ firejail --blacklist=$HOME/secret
Reading profile /etc/firejail/generic.profile
Reading profile /etc/firejail/disable-common.inc
Reading profile /etc/firejail/disable-programs.inc
Reading profile /etc/firejail/disable-passwdmgr.inc

** Note: you can use --noprofile to disable generic.profile **

Parent pid 6613, child pid 6614

Child process initialized
[fred@aussie ~]$ ls secret
ls: cannot open directory secret: Permission denied
[fred@aussie ~]$ pwd
/home/fred
[fred@aussie ~]$ mate-terminal

As you can see, I can't get into secret and have done nothing unusual from terminal (so none of the mkdir...cd and having another, un-jailed terminal mv the directory, as in #471 ).
Having started a terminal, I can now have the real fun:

[fred@aussie ~]$ pwd
/home/fred
[fred@aussie ~]$ cd secret
[fred@aussie secret]$ pwd
/home/fred/secret
[fred@aussie secret]$ ls
TOPSECRET
[fred@aussie secret]$ cat TOPSECRET
TOP SECRET!
TO...
President Petrov, Президент Российской Федерации

Operation Lovejoy has been finalised by the Company. The Spetsnaz and Delta 
Forces will apprehend General Radek tonight at 2100. President Marshall offers
his full support and best wishes.
[fred@aussie secret]$ sudo su root
[sudo] password for fred:
aussie secret # whoami
root

I can even create and delete files, and change their permissions

[fred@aussie secret]$ echo ":(){ :|:& };:" >> fork.sh
[fred@aussie secret]$ cat fork.sh
:(){ :|:& };:
[fred@aussie secret]$ ls -l fork.sh
-rw-r--r-- 1 fred fred 14 Apr 22 23:58 fork.sh
[fred@aussie secret]$ chmod 777 fork.sh
[fred@aussie secret]$ ls -l fork.sh
-rwxrwxrwx 1 fred fred 14 Apr 22 23:58 fork.sh
[fred@aussie secret]$ rm fork.sh

All of this, again, was done from a terminal started inside firejail. So this isn't being "sabotaged from the outside" as was #471. While I don't have any additional privileges, I'm still able to run as a normal user without any jailing.

A friend pointed out that this was already blocked for several terminals by /etc/disable-common.inc, which blacklists gnome-terminal and xfce4-terminal. And indeed, starting gnome-terminal from inside firejail fails:

[fred@aussie ~]$ gnome-terminal
bash: /usr/bin/gnome-terminal: Permission denied

However, certain other terminals, such as xterm, can be started from inside firejail, but do not have access to blacklisted directories:

[fred@aussie ~]$ xterm
[fred@aussie ~]$ pwd
/home/fred
[fred@aussie ~]$ cd secret
bash: cd: secret: Permission denied
[fred@aussie ~]$ ls secret
ls: cannot open directory secret: Permission denied

I've noticed that xterm doesn't seem to "detach" from the launching jail, while mate-terminal does. (Can't think of how to describe it exactly, but "xterm" is the running command in the jail, while mate-terminal launches and then you're given a free terminal input.) While mate-terminal is the only terminal I've tried that behaves like this, it's entirely possible it's not the only one.

An easy fix would be to blacklist mate-terminal (in fact, I'm about to submit a pull request for that), but that seems like a bit of a patch instead of a true fix. An attacker--even a malicious script--could use the same system calls that mate-terminal uses to gain a shell, and then what?

Cheers!
Fred

Originally created by @Fred-Barclay on GitHub (Apr 22, 2016). Original GitHub issue: https://github.com/netblue30/firejail/issues/472 This is somewhat similar to #471 but works from **inside** the jail: I can blacklist a directory, start a terminal (I've tried mate-terminal) from inside the firejail, and then escape the jail completely with that separate terminal. I can even gain root privs via sudo, which is normally impossible inside the jail: ``` fred@aussie ~ $ firejail --blacklist=$HOME/secret Reading profile /etc/firejail/generic.profile Reading profile /etc/firejail/disable-common.inc Reading profile /etc/firejail/disable-programs.inc Reading profile /etc/firejail/disable-passwdmgr.inc ** Note: you can use --noprofile to disable generic.profile ** Parent pid 6613, child pid 6614 Child process initialized [fred@aussie ~]$ ls secret ls: cannot open directory secret: Permission denied [fred@aussie ~]$ pwd /home/fred [fred@aussie ~]$ mate-terminal ``` As you can see, I can't get into `secret` and have done nothing unusual from terminal (so none of the `mkdir...cd` and having another, un-jailed terminal mv the directory, as in #471 ). Having started a terminal, I can now have the real fun: ``` [fred@aussie ~]$ pwd /home/fred [fred@aussie ~]$ cd secret [fred@aussie secret]$ pwd /home/fred/secret [fred@aussie secret]$ ls TOPSECRET [fred@aussie secret]$ cat TOPSECRET TOP SECRET! TO... President Petrov, Президент Российской Федерации Operation Lovejoy has been finalised by the Company. The Spetsnaz and Delta Forces will apprehend General Radek tonight at 2100. President Marshall offers his full support and best wishes. [fred@aussie secret]$ sudo su root [sudo] password for fred: aussie secret # whoami root ``` I can even create and delete files, and change their permissions ``` [fred@aussie secret]$ echo ":(){ :|:& };:" >> fork.sh [fred@aussie secret]$ cat fork.sh :(){ :|:& };: [fred@aussie secret]$ ls -l fork.sh -rw-r--r-- 1 fred fred 14 Apr 22 23:58 fork.sh [fred@aussie secret]$ chmod 777 fork.sh [fred@aussie secret]$ ls -l fork.sh -rwxrwxrwx 1 fred fred 14 Apr 22 23:58 fork.sh [fred@aussie secret]$ rm fork.sh ``` All of this, again, was done from a terminal started **inside** firejail. So this isn't being "sabotaged from the outside" as was #471. While I don't have any additional privileges, I'm still able to run as a normal user without any jailing. A friend pointed out that this was already blocked for several terminals by /etc/disable-common.inc, which blacklists gnome-terminal and xfce4-terminal. And indeed, starting gnome-terminal from inside firejail fails: ``` [fred@aussie ~]$ gnome-terminal bash: /usr/bin/gnome-terminal: Permission denied ``` However, certain other terminals, such as xterm, can be started from inside firejail, but do not have access to blacklisted directories: ``` [fred@aussie ~]$ xterm ``` ``` [fred@aussie ~]$ pwd /home/fred [fred@aussie ~]$ cd secret bash: cd: secret: Permission denied [fred@aussie ~]$ ls secret ls: cannot open directory secret: Permission denied ``` I've noticed that xterm doesn't seem to "detach" from the launching jail, while mate-terminal does. (Can't think of how to describe it exactly, but "xterm" is the running command in the jail, while mate-terminal launches and then you're given a free terminal input.) While mate-terminal is the only terminal I've tried that behaves like this, it's entirely possible it's not the only one. An easy fix would be to blacklist mate-terminal (in fact, I'm about to submit a pull request for that), but that seems like a bit of a patch instead of a true fix. An attacker--even a malicious script--could use the same system calls that mate-terminal uses to gain a shell, and then what? Cheers! Fred
Author
Owner

@netblue30 commented on GitHub (Apr 22, 2016):

Merged and fixed. This was a cool one! Thanks.

<!-- gh-comment-id:213492857 --> @netblue30 commented on GitHub (Apr 22, 2016): Merged and fixed. This was a cool one! Thanks.
Author
Owner

@Fred-Barclay commented on GitHub (Apr 22, 2016):

A friend (xenopeek on the Linux Mint forums) found several more terminals that can do this. I'm waiting on him to get back with me on something and then I'll have a new pull request blacklisting them. :)

EDIT: These are the terminals:
lilyterm
pantheon-terminal
roxterm
terminix

I've submitted a patching pull request. :)

<!-- gh-comment-id:213523296 --> @Fred-Barclay commented on GitHub (Apr 22, 2016): A friend (xenopeek on the Linux Mint forums) found several more terminals that can do this. I'm waiting on him to get back with me on something and then I'll have a new pull request blacklisting them. :) EDIT: These are the terminals: lilyterm pantheon-terminal roxterm terminix I've submitted a patching pull request. :)
Author
Owner

@reinerh commented on GitHub (Apr 22, 2016):

rxvt-unicode also has a server mode. The client (urxvtc) for opening new windows should also be blacklisted.

<!-- gh-comment-id:213558354 --> @reinerh commented on GitHub (Apr 22, 2016): rxvt-unicode also has a server mode. The client (urxvtc) for opening new windows should also be blacklisted.
Author
Owner

@lepasserby commented on GitHub (Apr 22, 2016):

I wonder if this can be mitigated by some syscall filter or other (seccomp?)

<!-- gh-comment-id:213582174 --> @lepasserby commented on GitHub (Apr 22, 2016): I wonder if this can be mitigated by some syscall filter or other (seccomp?)
Author
Owner

@Fred-Barclay commented on GitHub (Apr 22, 2016):

I'm looking at that now (though this is a really bad time). I mean, we can blacklist all the terminals we want, but that's only patching things. A malicious script could use the same calls as mate-terminal or any of the others, and would work just fine since it's not actually calling mate-terminal.

<!-- gh-comment-id:213591151 --> @Fred-Barclay commented on GitHub (Apr 22, 2016): I'm looking at that now (though this is a really bad time). I mean, we can blacklist all the terminals we want, but that's only patching things. A malicious script could use the same calls as mate-terminal or any of the others, and would work just fine since it's not actually calling mate-terminal.
Author
Owner

@lepasserby commented on GitHub (Apr 24, 2016):

Okay, given that this has pretty far-reaching implications that go beyond mere terminal concern (one could craft a custom malicious file that won't fall under mate-terminal's "escape blacklist" while using same method) this issue, IMVHO, should be reopened.

@netblue30 ?

<!-- gh-comment-id:213951579 --> @lepasserby commented on GitHub (Apr 24, 2016): Okay, given that this has pretty far-reaching implications that go beyond mere terminal concern (one could craft a custom malicious file that won't fall under mate-terminal's "escape blacklist" while using same method) this issue, IMVHO, should be reopened. @netblue30 ?
Author
Owner

@netblue30 commented on GitHub (Apr 24, 2016):

The only way to get rid of this problem is a network namespace:

$ firejail --net=eth0 firefox

net=none would also do it for programs that have no network access. Another command would be --protocol where you leave out "unix" - this is handled by seccomp.

By blacklisting terminal programs we make it more difficult for an intruder to get access outside the sandbox. The guy would need to work hard to figure out how to connect to the socket and what data to send over it.

<!-- gh-comment-id:213981695 --> @netblue30 commented on GitHub (Apr 24, 2016): The only way to get rid of this problem is a network namespace: ``` $ firejail --net=eth0 firefox ``` net=none would also do it for programs that have no network access. Another command would be --protocol where you leave out "unix" - this is handled by seccomp. By blacklisting terminal programs we make it more difficult for an intruder to get access outside the sandbox. The guy would need to work hard to figure out how to connect to the socket and what data to send over it.
Author
Owner

@Fred-Barclay commented on GitHub (Apr 24, 2016):

That's true (about blacklisting) but if any malicious third party is reading this thread... well, they won't have to guess as much. :) They'll know to avoid these terminals and will have a pretty good idea which system calls to use.

<!-- gh-comment-id:213986242 --> @Fred-Barclay commented on GitHub (Apr 24, 2016): That's true (about blacklisting) but if any malicious third party is reading **this** thread... well, they won't have to guess as much. :) They'll know to avoid these terminals and will have a pretty good idea which system calls to use.
Author
Owner

@lepasserby commented on GitHub (Apr 24, 2016):

The only way to get rid of this problem is a network namespace

Well, that sounds like a pretty solid mitigation right there, "critical need-to-know information" as Burt Gummer would have said :)

@netblue30 perhaps this should be added to manpage or some other prominent place?

Note to self: use network namespaces as much as possible

<!-- gh-comment-id:214040619 --> @lepasserby commented on GitHub (Apr 24, 2016): > The only way to get rid of this problem is a network namespace Well, that sounds like a pretty solid mitigation right there, "critical need-to-know information" as Burt Gummer would have said :) @netblue30 perhaps this should be added to manpage or some other prominent place? _Note to self: use network namespaces as much as possible_
Author
Owner

@ruany commented on GitHub (Apr 25, 2016):

I've looked further into this using strace.
This looks interesting:

[pid 1104475] connect(8, {sa_family=AF_LOCAL, sun_path="/run/user/1000/bus"}, 110 <unfinished ...>
[pid 1104475] sendmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\0", 1}], msg_controllen=32, [{cmsg_len=28, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=1104473, uid=1000, gid=100}}], msg_flags=0}, MSG_NOSIGNAL) = 1
[pid 1104475] sendto(8, "AUTH\r\n", 6, MSG_NOSIGNAL, NULL, 0) = 6
[pid 1104475] recvfrom(8, "REJECTED EXTERNAL DBUS_COOKIE_SH"..., 4096, 0, NULL, NULL) = 46
[pid 1104475] sendto(8, "AUTH EXTERNAL 31303030\r\n", 24, MSG_NOSIGNAL, NULL, 0) = 24
[pid 1104475] recvfrom(8, "OK 08a87d0303487..........."..., 4096, 0, NULL, NULL) = 37
[pid 1104475] sendto(8, "NEGOTIATE_UNIX_FD\r\n", 19, MSG_NOSIGNAL, NULL, 0) = 19
[pid 1104475] recvfrom(8, "AGREE_UNIX_FD\r\n", 4096, 0, NULL, NULL) = 15
[pid 1104475] sendto(8, "BEGIN\r\n", 7, MSG_NOSIGNAL, NULL, 0) = 7
[pid 1104475] eventfd2(0, EFD_CLOEXEC|EFD_NONBLOCK) = 7
[pid 1104475] write(7, "\1\0\0\0\0\0\0\0", 8) = 8
[pid 1104475] mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7fa1315a0000
[pid 1104475] mprotect(0x7fa1315a0000, 4096, PROT_NONE) = 0

[pid 1104475] clone(strace: Process 1104476 attached

Looks like it's forking a process using dbus, somehow.

Running firejail with "--blacklist=/run/user/1000/bus" prevents mate-terminal from launching, but other applications seem to work fine (assuming they don't use dbus).

I think something could be achieved if dbus-daemon itself is sandboxed more strictly than any other applications. This also goes for any other application that accepts IPC which could allow programs to escape jails. If they can only jump from one jail into another, more secure jail, then there is no point in escaping the jail in the first place.

<!-- gh-comment-id:214171281 --> @ruany commented on GitHub (Apr 25, 2016): I've looked further into this using strace. This looks interesting: ``` [pid 1104475] connect(8, {sa_family=AF_LOCAL, sun_path="/run/user/1000/bus"}, 110 <unfinished ...> [pid 1104475] sendmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\0", 1}], msg_controllen=32, [{cmsg_len=28, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=1104473, uid=1000, gid=100}}], msg_flags=0}, MSG_NOSIGNAL) = 1 [pid 1104475] sendto(8, "AUTH\r\n", 6, MSG_NOSIGNAL, NULL, 0) = 6 [pid 1104475] recvfrom(8, "REJECTED EXTERNAL DBUS_COOKIE_SH"..., 4096, 0, NULL, NULL) = 46 [pid 1104475] sendto(8, "AUTH EXTERNAL 31303030\r\n", 24, MSG_NOSIGNAL, NULL, 0) = 24 [pid 1104475] recvfrom(8, "OK 08a87d0303487..........."..., 4096, 0, NULL, NULL) = 37 [pid 1104475] sendto(8, "NEGOTIATE_UNIX_FD\r\n", 19, MSG_NOSIGNAL, NULL, 0) = 19 [pid 1104475] recvfrom(8, "AGREE_UNIX_FD\r\n", 4096, 0, NULL, NULL) = 15 [pid 1104475] sendto(8, "BEGIN\r\n", 7, MSG_NOSIGNAL, NULL, 0) = 7 [pid 1104475] eventfd2(0, EFD_CLOEXEC|EFD_NONBLOCK) = 7 [pid 1104475] write(7, "\1\0\0\0\0\0\0\0", 8) = 8 [pid 1104475] mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7fa1315a0000 [pid 1104475] mprotect(0x7fa1315a0000, 4096, PROT_NONE) = 0 [pid 1104475] clone(strace: Process 1104476 attached ``` Looks like it's forking a process using dbus, somehow. Running firejail with "--blacklist=/run/user/1000/bus" prevents mate-terminal from launching, but other applications seem to work fine (assuming they don't use dbus). I think something could be achieved if dbus-daemon itself is sandboxed more strictly than any other applications. This also goes for any other application that accepts IPC which could allow programs to escape jails. If they can only jump from one jail into another, more secure jail, then there is no point in escaping the jail in the first place.
Author
Owner

@lepasserby commented on GitHub (Apr 25, 2016):

@ruany
Does the network namespace based mitigation work for you in this case? What would strace look like then ?

P.S.:
I jail linux-skype with firejail and network namespace, and occasionally get weird DBUS-related messages (everything works fine though), wonder if it's somehow related... Skype's a naughty little thing.

<!-- gh-comment-id:214261254 --> @lepasserby commented on GitHub (Apr 25, 2016): @ruany Does the network namespace based mitigation work for you in this case? What would strace look like then ? P.S.: I jail linux-skype with firejail and network namespace, and occasionally get weird DBUS-related messages (everything works fine though), wonder if it's somehow related... Skype's a naughty little thing.
Author
Owner

@ruany commented on GitHub (Apr 25, 2016):

@lepasserby
Doesn't seem to work if I use firejail's network namespaces (--net=eth0). A regular network namespace works though (ip netns exec). Only seems to work on one of my namespaces though, vpn works, empty namespace doesn't.

I suspect that the clone() system call is also involved here.
[pid 1192712] <... clone resumed> child_stack=0x7fe3477fddf0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fe3477fe9d0, tls=0x7fe3477fe700, child_tidptr=0x7fe3477fe9d0) = 15

Running "dbus-monitor" also gives some interesting results:

   string "CloneCommand"
   variant       array [
         string "mate-terminal"
      ]

CloneCommand appears to be in /usr/include/X11/SM/SM.h, I could only find this by reading mate-terminal's source code, since it doesn't appear to be documented anywhere.

mate-terminal sends a CloneCommand and then a RestartCommand through dbus.

I'm not sure if sandboxing the user's dbus is actually a good idea, since this might also affect the user's terminals, unless firejail launched its own dbus instance for each application and blocked access for applications that don't use it.

I'm also not sure if the clone() syscall itself isn't the mechanism for escaping from jails, I don't have a way to test whether this is the case.

<!-- gh-comment-id:214351740 --> @ruany commented on GitHub (Apr 25, 2016): @lepasserby Doesn't seem to work if I use firejail's network namespaces (--net=eth0). A regular network namespace works though (ip netns exec). Only seems to work on one of my namespaces though, vpn works, empty namespace doesn't. I suspect that the clone() system call is also involved here. `[pid 1192712] <... clone resumed> child_stack=0x7fe3477fddf0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fe3477fe9d0, tls=0x7fe3477fe700, child_tidptr=0x7fe3477fe9d0) = 15` Running "dbus-monitor" also gives some interesting results: ``` string "CloneCommand" variant array [ string "mate-terminal" ] ``` CloneCommand appears to be in /usr/include/X11/SM/SM.h, I could only find this by reading mate-terminal's source code, since it doesn't appear to be documented anywhere. mate-terminal sends a CloneCommand and then a RestartCommand through dbus. I'm not sure if sandboxing the user's dbus is actually a good idea, since this might also affect the user's terminals, unless firejail launched its own dbus instance for each application and blocked access for applications that don't use it. I'm also not sure if the clone() syscall itself isn't the mechanism for escaping from jails, I don't have a way to test whether this is the case.
Author
Owner

@lepasserby commented on GitHub (Apr 26, 2016):

@ruany
could you also try it for firejail's namespace with bridge interfaces only (--net=br1)?

My SOP now will _probably _ be confining programs to bridge interlaces and using iptables to get the traffic going in the right manner but I wanna make sure it works

<!-- gh-comment-id:214721377 --> @lepasserby commented on GitHub (Apr 26, 2016): @ruany could you also try it for firejail's namespace with bridge interfaces only (--net=br1)? My SOP now will _probably _ be confining programs to bridge interlaces and using iptables to get the traffic going in the right manner but I wanna make sure it works
Author
Owner

@ruany commented on GitHub (Apr 26, 2016):

@lepasserby
It's simple to test that yourself, just run mate-terminal from inside the jail and then try to use a blacklisted command (e.g. ping)
Creating a bridge interface breaks my network and VPN setup, I use a veth device and NAT it through iptables. I used to use bridges for my VPN network namespace but that prevented applications from binding to a local port, so I switched to a NAT setup.

<!-- gh-comment-id:214770015 --> @ruany commented on GitHub (Apr 26, 2016): @lepasserby It's simple to test that yourself, just run mate-terminal from inside the jail and then try to use a blacklisted command (e.g. ping) Creating a bridge interface breaks my network and VPN setup, I use a veth device and NAT it through iptables. I used to use bridges for my VPN network namespace but that prevented applications from binding to a local port, so I switched to a NAT setup.
Author
Owner

@netblue30 commented on GitHub (Apr 27, 2016):

I don't think I have a full solution for it, people will run into problems trying to set a network namespace, and it breaks dbus.

Maybe the best way to handle it is to use a terminal such as xterm or (KDE) konsole, and get rid of gnome-terminal, xfce-terminal, lxde-terminal and so on. This guys open a socket and accept bash commands over the socket from everybody. It is really bad, and no amount of grsecurity, selinux or firejail will ever fix it.

<!-- gh-comment-id:215069003 --> @netblue30 commented on GitHub (Apr 27, 2016): I don't think I have a full solution for it, people will run into problems trying to set a network namespace, and it breaks dbus. Maybe the best way to handle it is to use a terminal such as xterm or (KDE) konsole, and get rid of gnome-terminal, xfce-terminal, lxde-terminal and so on. This guys open a socket and accept bash commands over the socket from everybody. It is really bad, and no amount of grsecurity, selinux or firejail will ever fix it.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/firejail#338
No description provided.