[GH-ISSUE #4474] Exit code 255 instead of real exit code for signals #2679

Open
opened 2026-05-05 09:20:24 -06:00 by gitea-mirror · 8 comments
Owner

Originally created by @cgr71ii on GitHub (Aug 18, 2021).
Original GitHub issue: https://github.com/netblue30/firejail/issues/4474

I have noticed that when a signal (e.g. SIGABRT) stops the execution of a program, firejail does not exit with the same exit code that the binary, but always with 255. It is very useful to have the same exit code since this is the way differents errors can be detected (e.g. LAVA-M dataset) or even just signals like I said.

Bug and expected behavior
I just wrote a simple C++ program because I noticed this behaviour and it remains with this simple code:

#include <iostream>
#include <cstring>

using std::cout;
using std::string;
using std::endl;

int main(int argc, char** argv)
{
  char* a = (char*)malloc(sizeof(char*) * 10);

  strcpy(a, argv[1]);

  cout << "a: " << a << endl;

  free(a);

  return 0;
}
g++ file.c -o file

# Normal execution -> exit code 134 -> signal 6 (SIGABRT)
./file $(python -c 'print("a"*100)')

# Firejail execution -> exit code 255 ...
firejail ./file $(python -c 'print("a"*100)')

I think that the exit code 255 might be related to pull request described at https://github.com/netblue30/firejail/issues/358 since it returns -1 and this might be a data type problem (i.e. -1 short = 255 unsigned short), but I am not sure.

No profile and disabling firejail

  • What changed calling firejail --noprofile /path/to/program in a terminal?
    Still exit code 255
firejail --noprofile /path/to/file $(python -c 'print("a"*100)')
  • What changed calling the program by path (e.g. /usr/bin/vlc)?
    Nothing, the same behaviour.

Reproduce
Steps to reproduce the behavior: they are described above (i.e. copy example, compile and run with and without firejail).

Environment
lsb_release -a:
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal

uname -r:
5.11.0-27-generic

firejail --version:
firejail version 0.9.62

Compile time support:
- AppArmor support is enabled
- AppImage support is enabled
- chroot support is enabled
- file and directory whitelisting support is enabled
- file transfer support is enabled
- firetunnel support is enabled
- networking support is enabled
- overlayfs support is enabled
- private-home support is enabled
- seccomp-bpf support is enabled
- user namespace support is enabled
- X11 sandboxing support is enabled

Additional context
I need to know the exit code of the signals because I am using the LAVA-M dataset, which uses the exit code to know when different bugs have been triggered. Anyway, this should be a basic option of firejail, or at least that is what I think.

Originally created by @cgr71ii on GitHub (Aug 18, 2021). Original GitHub issue: https://github.com/netblue30/firejail/issues/4474 I have noticed that when a signal (e.g. SIGABRT) stops the execution of a program, firejail does not exit with the same exit code that the binary, but always with 255. It is very useful to have the same exit code since this is the way differents errors can be detected (e.g. LAVA-M dataset) or even just signals like I said. **Bug and expected behavior** I just wrote a simple C++ program because I noticed this behaviour and it remains with this simple code: ```c++ #include <iostream> #include <cstring> using std::cout; using std::string; using std::endl; int main(int argc, char** argv) { char* a = (char*)malloc(sizeof(char*) * 10); strcpy(a, argv[1]); cout << "a: " << a << endl; free(a); return 0; } ``` ```bash g++ file.c -o file # Normal execution -> exit code 134 -> signal 6 (SIGABRT) ./file $(python -c 'print("a"*100)') # Firejail execution -> exit code 255 ... firejail ./file $(python -c 'print("a"*100)') ``` I think that the exit code 255 might be related to pull request described at https://github.com/netblue30/firejail/issues/358 since it returns -1 and this might be a data type problem (i.e. -1 short = 255 unsigned short), but I am not sure. **No profile and disabling firejail** - What changed calling `firejail --noprofile /path/to/program` in a terminal? Still exit code 255 ```bash firejail --noprofile /path/to/file $(python -c 'print("a"*100)') ``` - What changed calling the program by path (e.g. `/usr/bin/vlc`)? Nothing, the same behaviour. **Reproduce** Steps to reproduce the behavior: they are described above (i.e. copy example, compile and run with and without firejail). **Environment** `lsb_release -a`: Distributor ID: Ubuntu Description: Ubuntu 20.04.2 LTS Release: 20.04 Codename: focal `uname -r`: 5.11.0-27-generic `firejail --version`: firejail version 0.9.62 Compile time support: - AppArmor support is enabled - AppImage support is enabled - chroot support is enabled - file and directory whitelisting support is enabled - file transfer support is enabled - firetunnel support is enabled - networking support is enabled - overlayfs support is enabled - private-home support is enabled - seccomp-bpf support is enabled - user namespace support is enabled - X11 sandboxing support is enabled **Additional context** I need to know the exit code of the signals because I am using the LAVA-M dataset, which uses the exit code to know when different bugs have been triggered. Anyway, this should be a basic option of firejail, or at least that is what I think.
gitea-mirror added the
bug
label 2026-05-05 09:20:24 -06:00
Author
Owner

@smitsohu commented on GitHub (Aug 28, 2021):

Hm, would it be ok to do the same as bash, and set exit code to 128+n where n is the signal number?

Just to provide a way to distinguish graceful child termination from a fatal signal.

<!-- gh-comment-id:907602039 --> @smitsohu commented on GitHub (Aug 28, 2021): Hm, would it be ok to do the same as bash, and set exit code to `128+n` where `n` is the signal number? Just to provide a way to distinguish graceful child termination from a fatal signal.
Author
Owner

@cgr71ii commented on GitHub (Aug 28, 2021):

That's exactly what I think that would be the best. It is true that an exit code 139 not always means SIGSEGV signal, since a developer can take the decision of using that exit code for some meaning, but that's a problem that everyone will face when executing a software (at least, using bash, that is the usual way. I do not really know how other shells handle the way they warn the user about signals).

<!-- gh-comment-id:907602608 --> @cgr71ii commented on GitHub (Aug 28, 2021): That's exactly what I think that would be the best. It is true that an exit code 139 not always means SIGSEGV signal, since a developer can take the decision of using that exit code for some meaning, but that's a problem that everyone will face when executing a software (at least, using bash, that is the usual way. I do not really know how other shells handle the way they warn the user about signals).
Author
Owner

@smitsohu commented on GitHub (Aug 28, 2021):

I checked some other shells, all of them do the same.

<!-- gh-comment-id:907631533 --> @smitsohu commented on GitHub (Aug 28, 2021): I checked some other shells, all of them do the same.
Author
Owner

@smitsohu commented on GitHub (Sep 12, 2021):

From looking at the exit code alone, it is impossible to know whether it refers to the sandboxed application or Firejail:

pstree
[...]
firejail───firejail───sandboxed_application

That's simply because there are usually three or more processes, but only one exit code. To solve this we would need to keep two strictly separate sets of return codes, one set for the sandboxed application and another set for Firejail.

Coreutils does something in the way, for tools that execute other programs. But it is limited to regular process exit, excluding fatal signals:

ac4841298e/src/system.h (L86-L93)

It's not a standard, but other tools like Docker also follow this convention. Do we want this as well? It could be added to the pull request.

<!-- gh-comment-id:917698063 --> @smitsohu commented on GitHub (Sep 12, 2021): From looking at the exit code _alone_, it is impossible to know whether it refers to the sandboxed application or Firejail: ``` pstree [...] firejail───firejail───sandboxed_application ``` That's simply because there are usually three or more processes, but only one exit code. To solve this we would need to keep two strictly separate sets of return codes, one set for the sandboxed application and another set for Firejail. Coreutils does something in the way, for tools that execute other programs. But it is limited to regular process exit, excluding fatal signals: https://github.com/coreutils/coreutils/blob/ac4841298e92ce057e27d56013ec5f4842231026/src/system.h#L86-L93 It's not a standard, but other tools like Docker also follow this convention. Do we want this as well? It could be added to the pull request.
Author
Owner

@cgr71ii commented on GitHub (Sep 13, 2021):

I understand what you are saying. I think that that approach does not solve the initial problem, since, at least in my case, I need to know the specific exit code to know which vulnerability I discovered. Besides, the current behaviour is to return the exit code of the sandboxed program, the only problem is with the singnals, so I think it is not appropriate to change the whole behaviour of Firejail to a set of encoded codes for the exit code because it will make lose control and/or information when running a sandboxed program.

Maybe, the approach of return multiple exit codes is feasible. Check this out: https://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another

<!-- gh-comment-id:917904962 --> @cgr71ii commented on GitHub (Sep 13, 2021): I understand what you are saying. I think that that approach does not solve the initial problem, since, at least in my case, I need to know the specific exit code to know which vulnerability I discovered. Besides, the current behaviour is to return the exit code of the sandboxed program, the only problem is with the singnals, so I think it is not appropriate to change the whole behaviour of Firejail to a set of encoded codes for the exit code because it will make lose control and/or information when running a sandboxed program. Maybe, the approach of return multiple exit codes is feasible. Check this out: https://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another
Author
Owner

@cdellacqua commented on GitHub (Sep 15, 2021):

I'm having a similar problem, maybe in a simpler scenario. I created a script with a trap on SIGINT and SIGTERM that does some cleanup before exiting with code 0.

Here is a simplified version of that script:

#!/bin/sh

cleanup() {
	echo 'bye'
	exit 0
}

trap cleanup TERM INT

echo 'hello!'
sleep 10000

Firejail correctly propagates signals to the child process, for example if you run this script and press Ctrl+C to send a SIGINT, the message 'bye' gets displayed, but the exit code read after that is 2 (SIGINT).

I agree with @cgr71ii that firejail should transparently return the exit code of the sandboxed process in this case, just like it already does when signals are not involved and the sandboxed processes exit "naturally".

<!-- gh-comment-id:919973459 --> @cdellacqua commented on GitHub (Sep 15, 2021): I'm having a similar problem, maybe in a simpler scenario. I created a script with a trap on SIGINT and SIGTERM that does some cleanup before exiting with code 0. Here is a simplified version of that script: ```sh #!/bin/sh cleanup() { echo 'bye' exit 0 } trap cleanup TERM INT echo 'hello!' sleep 10000 ``` Firejail correctly propagates signals to the child process, for example if you run this script and press Ctrl+C to send a SIGINT, the message 'bye' gets displayed, but the exit code read after that is 2 (SIGINT). I agree with @cgr71ii that firejail should transparently return the exit code of the sandboxed process in this case, just like it already does when signals are not involved and the sandboxed processes exit "naturally".
Author
Owner

@smitsohu commented on GitHub (Sep 16, 2021):

@cgr71ii

I think that that approach does not solve the initial problem

Right, it has nothing to do with your issue, let's put it to the backlog.

@cdellacqua

I agree, Firejail should preferably just return the exit code of the sandboxed app. Let me give it a try.

<!-- gh-comment-id:920872951 --> @smitsohu commented on GitHub (Sep 16, 2021): @cgr71ii > I think that that approach does not solve the initial problem Right, it has nothing to do with your issue, let's put it to the backlog. @cdellacqua I agree, Firejail should preferably just return the exit code of the sandboxed app. Let me give it a try.
Author
Owner

@smitsohu commented on GitHub (Sep 23, 2021):

Reopening because signal handler still doesn't return exit status of sandboxed app (the issue brought up by @cdellacqua).

<!-- gh-comment-id:925760451 --> @smitsohu commented on GitHub (Sep 23, 2021): Reopening because signal handler still doesn't return exit status of sandboxed app (the issue brought up by @cdellacqua).
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#2679
No description provided.