Jail and monitor your applications

Seamless Overview

© Lead Image © hywards, 123RF.com

© Lead Image © hywards, 123RF.com

Article from Issue 281/2024

Software from unknown sources always poses some risks. With the strace analysis tool and the Firejail sandbox, you can monitor and isolate unknown applications to safeguard your system.

Malware can occasionally become an issue for Linux users. If you download software package from third-party providers then install them manually rather than relying on a distribution's official standard repositories, you need to trust the provider. If you aren't sure, you can monitor these programs to check which files they open and which network connections they establish. Starting these tests in a sandbox also denies the program access to your physical system and private configuration files. This article looks at strace as a monitoring tool and Firejail as a sandbox.

Finding Traces

The strace [1] system call tracer can be used to discover which software accesses which files. As an example, I'll show you how to use strace to find out which files the passwd command opens when you change your password.

Open two terminal windows and enter passwd as a normal user in one window. Do not answer the prompts for the time being. Instead, pop up a second terminal and enter as root:

strace -yy -o passwd.log -p $(pidof passwd)

This starts logging for the passwd process in the first window; the tool writes the information to the passwd.log. Now enter the old password in the first window and then enter the new password twice.

After leaving passwd, analyze the logfile created by strace in the second window. In Figure 1, two grep calls show that the old password is abc123, while the new password is a49152bcbc. In addition, passwd has accessed six files in the /etc folder since logging began, including /etc/passwd and /etc/shadow (the latter file contains the cryptographic hashes of the passwords).

Figure 1: Strace sees everything: It finds both file operations as well as communication with the terminal via standard input and output.

As the example shows, strace can easily monitor processes that are already running. However, it is usually easier to integrate strace when launching the program. For example, line 1 in Listing 1 starts an SSH login on a computer named server42. Among other things, strace logs all network connections that are opened; you can see this by taking a look at the ssh.log file. Line 3 is a filter for lines that contain sin_addr. In the example, the program has opened connections to the local DNS server and to server42 (on IP

Listing 1

Opening a Connection

01 $ strace -o ssh.log ssh server42
02 [...]
03 $ grep ^connect.*sin_addr ssh.log
04 connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("")}, 16) = 0
05 connect(3, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("")}, 16) = 0

Strace Magic

But how does this logging work? Modern operating systems create a barrier between the hardware and the applications. For example, programs are not allowed to directly talk to a hard disk controller in order to read and search data blocks from a connected disk. Instead, each application has to be configured via system calls (syscalls for short) to ask the operating system for help. Syscalls are selected kernel functions that the program cannot use directly by making a normal function call. Instead, a more roundabout procedure is used here.

Each syscall supported by the operating system has a number that the program needs to write to a processor register. The arguments for the syscall are written to other registers. The program then executes a special machine language instruction, for example, syscall, sysenter, or a classic software interrupt 128 (in assembler: int 0x80). This switches the program from user mode to kernel mode.

At this point, the operating system takes control. In kernel mode, the OS has full access to the hardware. It uses the syscall number to find the appropriate syscall handler. After an authorization check, it then completes the task resulting from the arguments in other registers. Any return values are stored in another register.

After completing the task, the operating system switches from kernel mode back to user mode. The program then reads the return value and continues its work.

Listing 2 shows a test program in the C programming language that uses open() to open a file named /etc/os-release and read() to load up to 4,095 characters into a buffer. It then calls close() to close the file and calls write() to write the buffer content to the standard output (i.e., to the terminal window). The open(), read(), write(), and close() library functions call syscalls of the same name in the kernel, and strace can monitor their behavior.

Listing 2

C Test Program

#include <unistd.h>
#include <fcntl.h>
#define BUFSIZE 4096
int main () {
  char buf[BUFSIZE] = {0};
  int fd = open("/etc/os-release", O_RDONLY);
  int res = read(fd, buf, BUFSIZE-1);
  write(STDOUT_FILENO, buf, res);

If you compile the program and run it with strace, you will find the syscalls in the logfile that is created. Listing 3 shows the command for the call and the last lines from the logfile generated by strace. The return values of the function calls also appear in the log.

Listing 3

Strace Monitors File Access

$ strace -e trace=open,read,write,close -o /tmp/testprog.log ./testprog
PRETTY_NAME="Ubuntu 23.10"
$ tail -5 /tmp/testprog.log
open("/etc/os-release", O_RDONLY)       = 3
read(3, "PRETTY_NAME=\"Ubuntu 23.10\"\nNAME="..., 4095) = 393
close(3)                                = 0
write(1, "PRETTY_NAME=\"Ubuntu 23.10\"\nNAME="..., 393) = 393
+++ exited with 0 +++

If you monitor an application over a longer period of time, the logfile will tend to be very large. It makes sense to use filters during logging. To do so, specify which syscalls you want strace to log. Details can be found in the Filtering section of the strace manpage [2]. Table 1 shows some typical examples.

Table 1

Strace Filtering Options

strace -e trace=open,close

Only open() and close()

strace -e trace=file

All file operations

strace -e trace=network

All network operations

The -f (--follow-forks) option is also important. It tells strace to additionally monitor child processes. After all, the interesting things often do not happen in the application that was launched first, but further down in the process tree.


Firejail [3] lets you lock programs away in a jail or sandbox. Much like Docker and container-based virtualization in general, jail software lets you run programs in isolation from other applications. The view of the filesystem and the network can also be restricted. Firejail offers these features. Preparing the program profiles makes it easier to use Firejail – ideally, simply precede a program call with the firejail command. Firejail is available for installation in the standard repositories of many distributions.

Typing firejail launches a shell where network access is disabled and access to the Bash history is prohibited. These and other restrictive rules are defined by the default.profile, which Firejail loads for the newly launched shell. From default.profile, two additional rules are used via include lines. Figure 2 clearly shows that Bash, which is locked in the jail, can neither read the history nor ping a computer on the network.

Figure 2: No history, no ping: Firejail disables various functions.

In principle, software running in a jail still has access to the entire filesystem. The only exceptions to this are areas whose use you explicitly prohibit. As an alternative, you can define a private directory in which the program runs and from which it cannot break out. The --private option lets you do this; you can use it as shown in Listing 4.

Listing 4

Private Folder

$ mkdir ~/privat
$ firejail --private=$HOME/privat

This is particularly interesting for programs that you do not want to access your home directory. The folder specified after --private acts as a substitute home directory in the jail; the application can create subdirectories and store files there, but not in the entire home directory. This also effectively prevents the program from spying on your private data. Firejail also hides other users' private folders. If you add the --noprofile switch to the call, Firejail does not apply any rules from the standard profiles. In this case, for example, network tools such as ping will work.

If you run Firejail with a program name as an argument, the software looks for a suitable profile. The firejail-profiles package contains 1,200 profiles for a wide variety of applications. At startup, Firejail shows you which profile files it is using. For MPlayer, for example, there is the mplayer.profile file, which includes the generic rules from whitelist-player-common.inc (Figure 3). These rules apply to all media players and allow access to the download folder, for example.

Figure 3: If you launch MPlayer in the jail, Firejail uses the matching rule file which then references a profile version for all media players.

Firejail does not work with software that you install from Snap packages because it cannot find the binaries from the Snaps. Combining Firejail with strace also seems impossible at first glance, as an attempt to, for example, have them run MPlayer fails. The solution here is an strace feature that lets the monitor itself run with root privileges, while the monitored program is running on a normal user account. Listing 5 shows the command, which uses the strace -u (for user) option.

Listing 5

Strace and Firejail

$ sudo strace -f -u esser \
  -o mplayer.log \
  firejail \
  mplayer -idx big_buck_bunny.avi

Firejail offers numerous other options that you let you fine tune what to allow and what to prevent the software from doing  [4]. It is also useful to inspect the profiles in the /etc/firejail/ folder.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Tracing Tools

    Programs rarely reveal what they are doing in the background, but a few clever tools, of interest to both programmers and administrators, monitor this activity and log system functions.

  • strace

    Get started with strace by examining a pair of "Hello World" programs. Next month, in the second part of this two-part series, I'll take a deeper look at strace output.

  • Practical strace

    After "Hello World," you really need to look at system calls in more detail. In this second of two articles, we'll look at debugging in the real world.


    A little C code and the LD_PRELOAD variable let you customize library functions to modify program behavior.

  • How to Write a Rootkit

    Today’s rootkits infiltrate a target system at kernel level, thus escaping unwanted attention from administrators. Read on for a practical look at how a kernel rootkit really works.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More