[GH-ISSUE #2267] Why does calling getpgrp(2) from a sandboxed process return 0? #1516

Closed
opened 2026-05-05 08:10:49 -06:00 by gitea-mirror · 5 comments
Owner

Originally created by @mqudsi on GitHub (Nov 21, 2018).
Original GitHub issue: https://github.com/netblue30/firejail/issues/2267

Hi there! I'm a member of the fish dev team, and we're trying to understand why fish won't run under firejail.

As a shell, the most important job fish has launching and managing child processes (job control). That includes creating process groups, marshalling the terminal between various processes and process groups, etc. Part of this requires fish to be aware of its own pgid, but calls to getpgrp return 0 as the pgid instead of the actual pgroup when running under firejail.

From the setpgid(2) man page:

setpgid() sets the PGID of the process specified by pid to pgid. If pid is zero, then the process ID of the calling process is used. If pgid is zero, then the PGID of the process specified by pid is made the same as its process ID. If setpgid() is used to move a process from one process group to another (as is done by some shells when creating pipelines), both process groups must be part of the same session (see setsid(2) and credentials(7)). In this case, the pgid specifies an existing process group to be joined and the session ID of that group must match the session ID of the joining process.

The POSIX.1 version of getpgrp(), which takes no arguments, returns the PGID of the calling process.

As you can see, while 0 may be a valid value to pass into setpgid, it does not represent a valid pgrp in that case (instead it tells setpgid to use the calling application's process id) and it is not a valid result of a getpgrp.

While we can theoretically patch our entire codebase to try and handle cases where we call libc apis with 0 as the pgid in question, I'm trying to understand why this is happening in the first place (I also disagree with some fellow devs and users who feel this is a bug in fish and not a issue with firejail, as I put the onus on the sandbox to create as realistic an environment as possible to maximize compatibility with sandboxed applications).

Could you advise us on why this happens and what we are supposed to do with a 0 pgroup? Is there a way to prevent firejail from intercepting the call to getpgrp(2) for fish in its firejail profile given its needs as a shell?

cc @faho @santpent

Originally created by @mqudsi on GitHub (Nov 21, 2018). Original GitHub issue: https://github.com/netblue30/firejail/issues/2267 Hi there! I'm a member of the [fish](https://github.com/fish-shell/fish-shell) dev team, and we're trying to understand why [fish won't run under firejail](https://github.com/fish-shell/fish-shell/issues/5295). As a shell, the most important job fish has launching and managing child processes (job control). That includes creating process groups, marshalling the terminal between various processes and process groups, etc. Part of this requires fish to be aware of its own pgid, but calls to `getpgrp` return `0` as the pgid instead of the actual pgroup when running under firejail. From the setpgid(2) man page: >setpgid() sets the PGID of the process specified by pid to pgid. If pid is zero, then the process ID of the calling process is used. If pgid is zero, then the PGID of the process specified by pid is made the same as its process ID. If setpgid() is used to move a process from one process group to another (as is done by some shells when creating pipelines), both process groups must be part of the same session (see setsid(2) and credentials(7)). In this case, the pgid specifies an existing process group to be joined and the session ID of that group must match the session ID of the joining process. >The POSIX.1 version of getpgrp(), which takes no arguments, returns the PGID of the calling process. As you can see, while `0` may be a valid value to pass _into_ `setpgid`, it does not represent a valid pgrp in that case (instead it tells `setpgid` to use the calling application's *process id*) and it is not a valid result of a `getpgrp`. While we can theoretically patch our entire codebase to try and handle cases where we call libc apis with `0` as the pgid in question, I'm trying to understand why this is happening in the first place (I also disagree with some fellow devs and users who feel this is a bug in fish and not a issue with firejail, as I put the onus on the sandbox to create as realistic an environment as possible to maximize compatibility with sandboxed applications). Could you advise us on why this happens and what we are supposed to do with a 0 pgroup? Is there a way to prevent firejail from intercepting the call to getpgrp(2) for `fish` in its firejail profile given its needs as a shell? cc @faho @santpent
Author
Owner

@SkewedZeppelin commented on GitHub (Nov 21, 2018):

So firejail does no intercepting or shimming of syscalls, it can only restrict them via seccomp filters.

As for the original report (https://github.com/fish-shell/fish-shell/issues/5295), I can't actually reproduce it in anyway with fish 2.7.1 under Fedora 29. All of the following work just fine:

firejail fish
firejail --noprofile fish
firejail --shell=/usr/bin/fish
firejail --noprofile --shell=/usr/bin/fish

Maybe this is an AppArmor issue? @Vincent43

<!-- gh-comment-id:440837697 --> @SkewedZeppelin commented on GitHub (Nov 21, 2018): So firejail does no intercepting or shimming of syscalls, it can only restrict them via seccomp filters. As for the original report (https://github.com/fish-shell/fish-shell/issues/5295), I can't actually reproduce it in anyway with fish 2.7.1 under Fedora 29. All of the following work just fine: ``` firejail fish firejail --noprofile fish firejail --shell=/usr/bin/fish firejail --noprofile --shell=/usr/bin/fish ``` Maybe this is an AppArmor issue? @Vincent43
Author
Owner

@mqudsi commented on GitHub (Nov 21, 2018):

@SkewedZeppelin thanks for the reply and for checking in. fish 2.7.1 contained code that would assign fish to its own pgroup on launch, so it didn't run into this issue. You'd have to build it from master to run into it.

<!-- gh-comment-id:440838065 --> @mqudsi commented on GitHub (Nov 21, 2018): @SkewedZeppelin thanks for the reply and for checking in. fish 2.7.1 contained code that would assign fish to its own pgroup on launch, so it didn't run into this issue. You'd have to build it from `master` to run into it.
Author
Owner

@SkewedZeppelin commented on GitHub (Nov 21, 2018):

@mqudsi ah, apologies I missed that part

built from git, I can indeed reproduce when using the --shell option.

<!-- gh-comment-id:440838281 --> @SkewedZeppelin commented on GitHub (Nov 21, 2018): @mqudsi ah, apologies I missed that part built from git, I can indeed reproduce when using the --shell option.
Author
Owner

@crass commented on GitHub (Nov 21, 2018):

As @SkewedZeppelin noted, firejail is not intervening here.

~$ sudo --mount-proc -fp ps axo pid,pgrp,args
  PID  PGRP COMMAND
    1     0 ps axo pid,pgrp,args
~$ sudo unshare --mount-proc -fp /bin/bash
~# ps axo pid,pgrp,args
  PID  PGRP COMMAND
    1     1 /bin/bash
   11    11 ps axo pid,pgrp,args
~# exit
~$ sudo --mount-proc -fp /bin/dash
# ps axo pid,pgrp,args
  PID  PGRP COMMAND
    1     1 /bin/dash
    2     2 ps axo pid,pgrp,args
#
/bin/dash: 1: Cannot set tty process group (No such process)
~$ sudo unshare --mount-proc -fp /bin/dash +o monitor
# ps axo pid,pgrp,args
  PID  PGRP COMMAND
    1     0 /bin/dash +o monitor
    2     0 ps axo pid,pgrp,args

As can be seen from the first command, the first process in a new pid namespace has a process group of 0. The above commands show that both bash and dash change their process groups when job control is enabled (default), and that dash does not set the process group when job control is turned off.

On reviewing the dash source, setpgid is called when job control is turned on with the pgid being set to the pid of the main shell process.

I don't think this is an issue for most programs either way, but we could do a setpgid(0,1) right before spawning the jailed process. I suspect that would resolve these types of issues when a program wants to change a process group and then change it back to the previous process group id.

<!-- gh-comment-id:440855002 --> @crass commented on GitHub (Nov 21, 2018): As @SkewedZeppelin noted, firejail is not intervening here. ``` ~$ sudo --mount-proc -fp ps axo pid,pgrp,args PID PGRP COMMAND 1 0 ps axo pid,pgrp,args ~$ sudo unshare --mount-proc -fp /bin/bash ~# ps axo pid,pgrp,args PID PGRP COMMAND 1 1 /bin/bash 11 11 ps axo pid,pgrp,args ~# exit ~$ sudo --mount-proc -fp /bin/dash # ps axo pid,pgrp,args PID PGRP COMMAND 1 1 /bin/dash 2 2 ps axo pid,pgrp,args # /bin/dash: 1: Cannot set tty process group (No such process) ~$ sudo unshare --mount-proc -fp /bin/dash +o monitor # ps axo pid,pgrp,args PID PGRP COMMAND 1 0 /bin/dash +o monitor 2 0 ps axo pid,pgrp,args ``` As can be seen from the first command, the first process in a new pid namespace has a process group of `0`. The above commands show that both `bash` and `dash` change their process groups when job control is enabled (default), and that dash does not set the process group when job control is turned off. On reviewing the dash source, `setpgid` is called when job control is turned on with the `pgid` being set to the `pid` of the main shell process. I don't think this is an issue for most programs either way, but we could do a `setpgid(0,1)` right before spawning the jailed process. I suspect that would resolve these types of issues when a program wants to change a process group and then change it back to the previous process group id.
Author
Owner

@mqudsi commented on GitHub (Nov 22, 2018):

Thank you very much for the reply and the explanation. fish performs similar process group manipulations in interactive mode, but the apparent reuse of pgid 0 was running afoul of code that wasn't built with namespaces in mind.

Personally, my *nix flavor of choice is FreeBSD and I was wholly unfamiliar with the underpinnings of Linux namespaces. I'm still surprised that 0 is a valid user mode pgroup in the new namespace, as it invalidates the presumption that 0 is the kernel and 1 is init - a presumption hard baked into fish.

Thanks for taking the time to explain this! Hopefully fish 3.0 should work under firejail out-of-the-box once we get this addressed.

<!-- gh-comment-id:441117044 --> @mqudsi commented on GitHub (Nov 22, 2018): Thank you very much for the reply and the explanation. `fish` performs similar process group manipulations in interactive mode, but the apparent reuse of pgid 0 was running afoul of code that wasn't built with namespaces in mind. Personally, my *nix flavor of choice is FreeBSD and I was wholly unfamiliar with the underpinnings of Linux namespaces. I'm still surprised that 0 is a valid user mode pgroup in the new namespace, as it invalidates the presumption that 0 is the kernel and 1 is `init` - a presumption hard baked into `fish`. Thanks for taking the time to explain this! Hopefully fish 3.0 should work under firejail out-of-the-box once we get this addressed.
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#1516
No description provided.