Hide/Mask firejail process (pid 1) inside sandbox #7046

This commit is contained in:
netblue30 2026-02-02 07:39:36 -05:00
parent 4af62ee2da
commit d3f182543d
8 changed files with 171 additions and 1 deletions

View file

@ -412,6 +412,36 @@ path for the filename.
blue30/firejail/wiki/Creating-Profiles.
```
### --unhide-pid1
```text
--unhide-pid1
Pid 1 is always present inside Firejail sandbox. By restricting
access to /proc kernel interface, general tools like ps are un
able to view and access this process. --unhide-pid1 option dis
ables this functionality. Example:
$ firejail --name=test ### by default pid 1 is not visible
[...]
Child process initialized in 59.41 ms
$ ps a
PID TTY STAT TIME COMMAND
4 ? S 0:00 /bin/bash
5 ? R+ 0:00 ps a
$ exit
Parent is shutting down, bye…
$ firejail --name=test --unhide-pid1 ### pid 1 is visible
[...]
Child process initialized in 58.29 ms
$ ps a
PID TTY STAT TIME COMMAND
1 ? S 0:00 firejail --name=test --unhide-pid1
4 ? S 0:00 /bin/bash
6 ? R+ 0:00 ps a
$ exit
Parent is shutting down, bye…
```
### Landlock support - ongoing/experimental
* Added on #6078, which is based on #5315 from ChrysoliteAzalea/landlock

View file

@ -374,6 +374,7 @@ extern int arg_keep_fd_all; // inherit all file descriptors to sandbox
extern int arg_netlock; // netlocker
extern int arg_restrict_namespaces;
extern int arg_allow_bwrap;
extern int arg_unhide_pid1;
typedef enum {
DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus

View file

@ -801,6 +801,20 @@ void fs_proc_sys_dev_boot(void) {
disable_file(BLACKLIST_FILE, "/proc/mem");
disable_file(BLACKLIST_FILE, "/proc/kmem");
// hide the name of pid1
if (!arg_unhide_pid1) {
disable_file(BLACKLIST_FILE, "/proc/1/comm");
disable_file(BLACKLIST_FILE, "/proc/1/cmdline");
disable_file(BLACKLIST_FILE, "/proc/1/stat");
disable_file(BLACKLIST_FILE, "/proc/1/statm");
disable_file(BLACKLIST_FILE, "/proc/1/status");
disable_file(BLACKLIST_FILE, "/proc/1/task/1/comm");
disable_file(BLACKLIST_FILE, "/proc/1/task/1/cmdline");
disable_file(BLACKLIST_FILE, "/proc/1/task/1/stat");
disable_file(BLACKLIST_FILE, "/proc/1/task/1/statm");
disable_file(BLACKLIST_FILE, "/proc/1/task/1/status");
}
// remove kernel symbol information
if (!arg_allow_debuggers) {
disable_file(BLACKLIST_FILE, "/usr/src/linux");

View file

@ -170,6 +170,7 @@ int just_run_the_shell = 0;
int arg_netlock = 0;
int arg_restrict_namespaces = 0;
int arg_allow_bwrap = 0;
int arg_unhide_pid1 = 0;
int parent_to_child_fds[2];
int child_to_parent_fds[2];
@ -2314,6 +2315,8 @@ int main(int argc, char **argv, char **envp) {
arg_dbus_log_system = 1;
}
#endif
else if (strcmp(argv[i], "--unhide-pid1") == 0)
arg_unhide_pid1 = 1;
//*************************************
// network

View file

@ -3162,6 +3162,60 @@ $ firejail \-\-tree
.br
11970:netblue:transmission-gtk
.TP
\fB\-\-unhide\-pid1
Pid 1 is always present inside Firejail sandbox. By restricting access to
/proc kernel interface, general tools like ps are unable to view and access this process.
\-\-unhide\-pid1 option disables this functionality. Example:
.br
.br
$ firejail \-\-name=test ### by default pid 1 is not visible
.br
[...]
.br
Child process initialized in 59.41 ms
.br
$ ps a
.br
PID TTY STAT TIME COMMAND
.br
4 ? S 0:00 /bin/bash
.br
5 ? R+ 0:00 ps a
.br
$ exit
.br
Parent is shutting down, bye…
.br
.br
.br
$ firejail \-\-name=test \-\-unhide\-pid1 ### pid 1 is visible
.br
[...]
.br
Child process initialized in 58.29 ms
.br
$ ps a
.br
PID TTY STAT TIME COMMAND
.br
1 ? S 0:00 firejail \-\-name=test \-\-unhide\-pid1
.br
4 ? S 0:00 /bin/bash
.br
6 ? R+ 0:00 ps a
.br
$ exit
.br
Parent is shutting down, bye…
.br
.br
.TP
\fB\-\-version
Print program version/compile time support and exit.

View file

@ -31,6 +31,9 @@ sudo ls
echo "TESTING: seccomp @clock group (test/apps/seccomp-clock.exp)"
./seccomp-clock.exp
echo "TESTING: pid 1 functionality (test/apps/pid1.exp)"
./pid1.exp
# X11 apps
x11apps=(firefox qbittorrent firefox-xephyr galculator libreoffice firefox-xorg \
lowriter gimp inkscape emacs okular kdiff3 gpicview audacity \

View file

@ -16,7 +16,7 @@ expect {
timeout {puts "TESTING ERROR 1\n";exit}
-re "Child process initialized in \[0-9\]+.\[0-9\]+ ms"
}
sleep 5
sleep 8
spawn $env(SHELL)
send -- "firejail --list\r"

65
test/apps/pid1.exp Executable file
View file

@ -0,0 +1,65 @@
#!/usr/bin/expect -f
# This file is part of Firejail project
# Copyright (C) 2014-2026 Firejail Authors
# License GPL v2
set timeout 10
spawn $env(SHELL)
match_max 100000
send -- "firejail --name=test\r"
expect {
timeout {puts "TESTING ERROR 0\n";exit}
"Reading profile /etc/firejail/default.profile"
}
expect {
timeout {puts "TESTING ERROR 1\n";exit}
-re "Child process initialized in \[0-9\]+.\[0-9\]+ ms"
}
sleep 2
send -- "ps a\r"
expect {
timeout {puts "TESTING ERROR 3\n";exit}
"firejail --name=test" {puts "TESTING ERROR 4\n";exit}
"/bin/bash"
}
expect {
timeout {puts "TESTING ERROR 5\n";exit}
"ps a"
}
after 100
send -- "exit\r"
expect {
timeout {puts "TESTING ERROR 6\n";exit}
"Parent is shutting down"
}
sleep 1
send -- "firejail --name=test --unhide-pid1\r"
expect {
timeout {puts "TESTING ERROR 7\n";exit}
"Reading profile /etc/firejail/default.profile"
}
expect {
timeout {puts "TESTING ERROR 8\n";exit}
-re "Child process initialized in \[0-9\]+.\[0-9\]+ ms"
}
sleep 2
send -- "ps a\r"
expect {
timeout {puts "TESTING ERROR 9\n";exit}
"firejail --name=test --unhide-pid1"
}
after 100
send -- "exit\r"
expect {
timeout {puts "TESTING ERROR 11\n";exit}
"Parent is shutting down"
}
after 100
puts "\nall done\n"