[GH-ISSUE #2200] --read-only recursiveness does not cross filesystem boundaries #1471

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

Originally created by @iskunk on GitHub (Oct 17, 2018).
Original GitHub issue: https://github.com/netblue30/firejail/issues/2200

Consider a path /foo/bar/disk/, where disk is a mounted filesystem:

skunk@image-ubuntu64:~$ ls >/foo/good.txt
skunk@image-ubuntu64:~$ ls >/foo/bar/good.txt
skunk@image-ubuntu64:~$ ls >/foo/bar/disk/good.txt
skunk@image-ubuntu64:~$ find /foo -name good.txt
/foo/bar/disk/good.txt
find: ‘/foo/bar/disk/lost+found’: Permission denied
/foo/bar/good.txt
/foo/good.txt

skunk@image-ubuntu64:~$ firejail --hostname=fjtest --read-only=/foo
Reading profile /etc/firejail/default.profile
Reading profile /etc/firejail/disable-common.inc
Reading profile /etc/firejail/disable-passwdmgr.inc
Reading profile /etc/firejail/disable-programs.inc

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

Parent pid 2469, child pid 2470
Child process initialized in 16.93 ms
skunk@fjtest:~$ ls >/foo/bad.txt
bash: /foo/bad.txt: Read-only file system
skunk@fjtest:~$ ls >/foo/bar/bad.txt
bash: /foo/bar/bad.txt: Read-only file system
skunk@fjtest:~$ ls >/foo/bar/disk/bad.txt
skunk@fjtest:~$ ls -l /foo/bar/disk/bad.txt
-rw-r--r-- 1 skunk skunk 86 Oct 16 14:47 /foo/bar/disk/bad.txt

My expectation would be that --read-only=/foo prevents writing to /foo/bar/disk/, much as --blacklist=/foo prevents access to same.

This relates to issue #402, but the problem as described there relates to the /media directory and has a simple solution (use a wildcard). I'd like to bring attention to a trickier scenario: auto-mounted NFS directories. The situation is similar to the example presented above, except that mounts-within-mounts are common, and the depth at which they occur is arbitrary and unpredictable.

I'll share an example patterned after a real automount setup at my organization:

fileserve.example.com:/ on /nfs/fileserve.example.com type nfs (rw,nodev,addr=10.10.10.10)
fileserve.example.com:/vol/vol123 on /nfs/fileserve.example.com/vol/vol123 type nfs (rw,nodev,addr=10.10.10.10)

Not only would --read-only=/nfs not be sufficient, --read-only=/nfs/* also falls short. And --read-only=/nfs/*/*/* et al. is not practical.

I'd like the entire NFS tree to be accessible, but in a read-only manner to prevent writing anywhere I'd normally be able to. The current implementation of --read-only can't do this, and as the documentation gives the impression that it can, users may be caught unaware of the limitation.

Originally created by @iskunk on GitHub (Oct 17, 2018). Original GitHub issue: https://github.com/netblue30/firejail/issues/2200 Consider a path `/foo/bar/disk/`, where `disk` is a mounted filesystem: ``` skunk@image-ubuntu64:~$ ls >/foo/good.txt skunk@image-ubuntu64:~$ ls >/foo/bar/good.txt skunk@image-ubuntu64:~$ ls >/foo/bar/disk/good.txt skunk@image-ubuntu64:~$ find /foo -name good.txt /foo/bar/disk/good.txt find: ‘/foo/bar/disk/lost+found’: Permission denied /foo/bar/good.txt /foo/good.txt skunk@image-ubuntu64:~$ firejail --hostname=fjtest --read-only=/foo Reading profile /etc/firejail/default.profile Reading profile /etc/firejail/disable-common.inc Reading profile /etc/firejail/disable-passwdmgr.inc Reading profile /etc/firejail/disable-programs.inc ** Note: you can use --noprofile to disable default.profile ** Parent pid 2469, child pid 2470 Child process initialized in 16.93 ms skunk@fjtest:~$ ls >/foo/bad.txt bash: /foo/bad.txt: Read-only file system skunk@fjtest:~$ ls >/foo/bar/bad.txt bash: /foo/bar/bad.txt: Read-only file system skunk@fjtest:~$ ls >/foo/bar/disk/bad.txt skunk@fjtest:~$ ls -l /foo/bar/disk/bad.txt -rw-r--r-- 1 skunk skunk 86 Oct 16 14:47 /foo/bar/disk/bad.txt ``` My expectation would be that `--read-only=/foo` prevents writing to `/foo/bar/disk/`, much as `--blacklist=/foo` prevents access to same. This relates to issue #402, but the problem as described there relates to the `/media` directory and has a simple solution (use a wildcard). I'd like to bring attention to a trickier scenario: auto-mounted NFS directories. The situation is similar to the example presented above, except that mounts-within-mounts are common, and the depth at which they occur is arbitrary and unpredictable. I'll share an example patterned after a real automount setup at my organization: ``` fileserve.example.com:/ on /nfs/fileserve.example.com type nfs (rw,nodev,addr=10.10.10.10) fileserve.example.com:/vol/vol123 on /nfs/fileserve.example.com/vol/vol123 type nfs (rw,nodev,addr=10.10.10.10) ``` Not only would `--read-only=/nfs` not be sufficient, `--read-only=/nfs/*` also falls short. And `--read-only=/nfs/*/*/*` et al. is not practical. I'd like the entire NFS tree to be accessible, but in a read-only manner to prevent writing anywhere I'd normally be able to. The current implementation of `--read-only` can't do this, and as the documentation gives the impression that it can, users may be caught unaware of the limitation.
Author
Owner

@smitsohu commented on GitHub (Oct 17, 2018):

@iskunk Thank you for the report. Can I ask with which Firejail version you tried?

@netblue30 I wonder if Firejail could walk /proc/self/mountinfo bottom-up in order to remount all the child mount points. Its not perfect, but maybe it could be a pragmatic solution to all these issues with --noexec and --read-only.

<!-- gh-comment-id:430570981 --> @smitsohu commented on GitHub (Oct 17, 2018): @iskunk Thank you for the report. Can I ask with which Firejail version you tried? @netblue30 I wonder if Firejail could walk /proc/self/mountinfo bottom-up in order to remount all the child mount points. Its not perfect, but maybe it could be a pragmatic solution to all these issues with `--noexec` and `--read-only`.
Author
Owner

@netblue30 commented on GitHub (Oct 17, 2018):

We need to fix this. Let's walk /proc/self/mountinfo!

<!-- gh-comment-id:430620548 --> @netblue30 commented on GitHub (Oct 17, 2018): We need to fix this. Let's walk /proc/self/mountinfo!
Author
Owner

@iskunk commented on GitHub (Oct 17, 2018):

Hello @smitsohu, @netblue30!

I am using Firejail 0.9.52 as shipped with Ubuntu Bionic/18.04.

<!-- gh-comment-id:430704615 --> @iskunk commented on GitHub (Oct 17, 2018): Hello @smitsohu, @netblue30! I am using Firejail 0.9.52 as shipped with Ubuntu Bionic/18.04.
Author
Owner

@smitsohu commented on GitHub (Oct 21, 2018):

Ok, so there is a proof-of-concept at smitsohu@8a7293cf76bc20976bbc97a5e6110300e51fabfb

It looks quite ugly and there is probably plenty of room for optimizations, but it seems to work for most cases out of #402, #158, #833, #2029, #1529 and #1628 (not tested everything)

I don't have an NFS at hand, so I can't say if that would work as well.

<!-- gh-comment-id:431676920 --> @smitsohu commented on GitHub (Oct 21, 2018): Ok, so there is a proof-of-concept at smitsohu@8a7293cf76bc20976bbc97a5e6110300e51fabfb It looks quite ugly and there is probably plenty of room for optimizations, but it seems to work for most cases out of #402, #158, #833, #2029, #1529 and #1628 (not tested everything) I don't have an NFS at hand, so I can't say if that would work as well.
Author
Owner

@crass commented on GitHub (Oct 25, 2018):

Should we have a read-only-recursive or perhaps read-only-norec? I'm not actually sure if it would be useful, but it allows for backwards compatibility if it is. Also should read-write also be recursive for consistency?

<!-- gh-comment-id:432882658 --> @crass commented on GitHub (Oct 25, 2018): Should we have a `read-only-recursive` or perhaps `read-only-norec`? I'm not actually sure if it would be useful, but it allows for backwards compatibility if it is. Also should `read-write` also be recursive for consistency?
Author
Owner

@smitsohu commented on GitHub (Oct 25, 2018):

It looks quite ugly and there is probably plenty of room for optimizations,

Maybe the solution is to open the mount target, pick the mount id from /proc/self/fdinfo and jump right to the interesting lines in /proc/self/mountinfo. Then combine that with mount flag extraction, in order to not do unnecessary remounts. If this works it should avoid most of the problems with the current quick and dirty patch.

<!-- gh-comment-id:432993480 --> @smitsohu commented on GitHub (Oct 25, 2018): > It looks quite ugly and there is probably plenty of room for optimizations, Maybe the solution is to open the mount target, pick the mount id from /proc/self/fdinfo and jump right to the interesting lines in /proc/self/mountinfo. Then combine that with mount flag extraction, in order to not do unnecessary remounts. If this works it should avoid most of the problems with the current quick and dirty patch.
Author
Owner

@smitsohu commented on GitHub (Oct 25, 2018):

I think I have something, I will send a pull request.

<!-- gh-comment-id:433137611 --> @smitsohu commented on GitHub (Oct 25, 2018): I think I have something, I will send a pull request.
Author
Owner

@smitsohu commented on GitHub (Oct 26, 2018):

Should we have a read-only-recursive or perhaps read-only-norec? I'm not actually sure if it would be useful, but it allows for backwards compatibility if it is. Also should read-write also be recursive for consistency?

The new behaviour is not without problems in case of read-write. Take baloo_file.profile as an example. There we have

include disable-common.inc
...
# read-only  ${HOME}
# read-write ${HOME}/.local/share

If a user enables the last two lines, it will override the read-only ${HOME}/.local/share/applications and a number of other directives from disable-common.inc. In other words, the sequence of the directives is getting more important. This is probably something to keep in mind.

I'm going to update some profiles in the pull request to account for this (by moving read-write to the top).

<!-- gh-comment-id:433411903 --> @smitsohu commented on GitHub (Oct 26, 2018): > Should we have a read-only-recursive or perhaps read-only-norec? I'm not actually sure if it would be useful, but it allows for backwards compatibility if it is. Also should read-write also be recursive for consistency? The new behaviour is not without problems in case of `read-write`. Take baloo_file.profile as an example. There we have ``` include disable-common.inc ... # read-only ${HOME} # read-write ${HOME}/.local/share ``` If a user enables the last two lines, it will override the `read-only ${HOME}/.local/share/applications` and a number of other directives from disable-common.inc. In other words, the sequence of the directives is getting more important. This is probably something to keep in mind. I'm going to update some profiles in the pull request to account for this (by moving `read-write` to the top).
Author
Owner

@smitsohu commented on GitHub (Oct 26, 2018):

Moving to read-write to the top does not solve the problem if users have included it via a .local file. EDIT: doesn't apply, as all read-only directives are coming later when read-write is in the .local file.

Should read-write keep the old behavior? There could be a second option that does the mounts recursively.

<!-- gh-comment-id:433422964 --> @smitsohu commented on GitHub (Oct 26, 2018): ~~Moving to `read-write` to the top does not solve the problem if users have included it via a `.local` file.~~ EDIT: doesn't apply, as all `read-only` directives are coming later when `read-write` is in the `.local` file. Should `read-write` keep the old behavior? There could be a second option that does the mounts recursively.
Author
Owner

@iskunk commented on GitHub (Oct 26, 2018):

I was hoping, in #2202, that the order of options could be made less important rather than more. But I don't see a good alternative approach here.

It might be good if e.g. read-write ${HOME}/.local/share causes a warning to be printed that ${HOME}/.local/share/applications was previously marked read-only, so that at least the overrides are obvious to the user.

<!-- gh-comment-id:433469375 --> @iskunk commented on GitHub (Oct 26, 2018): I was hoping, in #2202, that the order of options could be made less important rather than more. But I don't see a good alternative approach here. It might be good if e.g. `read-write ${HOME}/.local/share` causes a warning to be printed that `${HOME}/.local/share/applications` was previously marked read-only, so that at least the overrides are obvious to the user.
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#1471
No description provided.