Add a path existence check, and if not, create the directory#1155
Add a path existence check, and if not, create the directory#1155t0hsumi wants to merge 1 commit into
Conversation
|
It solves the error described in this issue, but there is no binding between "a" and "tmp tmp." Also, after exiting the Bash shell, the program redirected unknown output to "output/tmp tmp." Below is my log with a debug flag. $ mkdir "a" "tmp tmp"
$ sudo mount --bind "a" "tmp tmp"
$ containerexec bash --debug
2025-03-09 21:30:13 - DEBUG - This is containerexec 3.29-dev.
2025-03-09 21:30:13 - INFO - Starting command bash
2025-03-09 21:30:13 - DEBUG - Available Cgroups: {}
2025-03-09 21:30:13 - DEBUG - Starting process.
2025-03-09 21:30:13 - DEBUG - Parent: child process of RunExecutor with PID 24036 started.
2025-03-09 21:30:13 - DEBUG - Child: child process of RunExecutor with PID 24036 started
2025-03-09 21:30:13 - DEBUG - Failed to make b'/tmp/BenchExec_run_knqnlkb1/mount/home/benchexec' a bind mount: [Errno 2] mount(b'/tmp/BenchExec_run_knqnlkb1/mount/home/benchexec', b'/tmp/BenchExec_run_knqnlkb1/mount/home/benchexec', None, 4096, None) failed: No such file or directory
2025-03-09 21:30:13 - DEBUG - Using fuse-overlayfs because of mount on '/'
2025-03-09 21:30:13 - DEBUG - /usr/bin/fuse-overlayfs version: 1.13
2025-03-09 21:30:13 - DEBUG - Creating overlay mount with /usr/bin/fuse-overlayfs: target=b'/tmp/BenchExec_run_knqnlkb1/overlayfs/fuse_mount', lower=b'/', upper=b'/tmp/BenchExec_run_knqnlkb1/temp', work=b'/tmp/BenchExec_run_knqnlkb1/overlayfs/fuse_work'
2025-03-09 21:30:13 - DEBUG - Mounting '/' as overlay
2025-03-09 21:30:13 - DEBUG - [Errno 16] umount(b'/tmp/BenchExec_run_knqnlkb1/mount/') failed: Device or resource busy
2025-03-09 21:30:13 - DEBUG - Mounting '/dev' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/dev/pts' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/dev/shm' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/dev/mqueue' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/dev/hugepages' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/run' as hidden
2025-03-09 21:30:13 - DEBUG - Mounting '/sys' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/kernel/security' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/fs/cgroup' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/fs/pstore' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/firmware/efi/efivars' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/fs/bpf' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/kernel/debug' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/kernel/tracing' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/fs/fuse/connections' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/sys/kernel/config' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/proc' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/bare/5' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/core20/2434' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/core20/2496' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/core22/1722' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/core22/1748' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/firefox/5437' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/firefox/5836' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/firmware-updater/167' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/gnome-42-2204/176' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/gtk-common-themes/1535' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/snap-store/1113' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/snap-store/1216' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/snapd-desktop-integration/247' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/snapd/23258' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/snapd/23771' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/snapd-desktop-integration/253' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/snap/thunderbird/682' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/var/snap/firefox/common/host-hunspell' as overlay
2025-03-09 21:30:13 - DEBUG - Cannot use overlay mode for /boot/efi because it has file system vfat. Using read-only mode instead. You can override this by specifying a different directory mode.
2025-03-09 21:30:13 - DEBUG - Mounting '/boot/efi' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/var/lib/lxcfs' as read-only
2025-03-09 21:30:13 - DEBUG - Mounting '/home/t0hsumi/prog/benchexec-dev/sample/tmp tmp' as overlay
2025-03-09 21:30:13 - DEBUG - Mounting '/tmp' as hidden
2025-03-09 21:30:13 - DEBUG - Mounting '/run' as hidden
2025-03-09 21:30:13 - DEBUG - Parent: executing bash in grand child with PID 24045 via child with PID 24036.
2025-03-09 21:30:13 - DEBUG - Waiting for signals
2025-03-09 21:30:13 - DEBUG - Waiting for signals
$ ls
a 'tmp tmp'
$ ls -al
total 8
drwxrwxr-x 4 benchexec benchexec 60 3月 9 21:30 .
drwxrwxr-x 5 benchexec benchexec 4096 3月 9 21:29 ..
drwxrwxr-x 2 benchexec benchexec 4096 3月 9 21:29 a
drwxrwxr-x 2 benchexec benchexec 80 3月 9 21:30 'tmp tmp'
$ echo "hello" > a/greeting
$ ls tmp\ tmp/
$ ls a
greeting
benchexec@benchexec:/home/t0hsumi/prog/benchexec-dev/sample$ exit
exit
2025-03-09 21:30:55 - DEBUG - Child: process bash terminated with exit code 0.
2025-03-09 21:30:55 - DEBUG - Transferring output file /proc/24036/root/tmp/BenchExec_run_knqnlkb1/home/t0hsumi/prog/benchexec-dev/sample/tmp tmp/.wh..wh..opq to output.files/tmp tmp/.wh..wh..opq
2025-03-09 21:30:55 - DEBUG - Transferring output file /proc/24036/root/tmp/BenchExec_run_knqnlkb1/home/t0hsumi/prog/benchexec-dev/sample/a/greeting to output.files/a/greeting
2025-03-09 21:30:55 - DEBUG - 2 output files matched the patterns and were transferred.
2025-03-09 21:30:55 - DEBUG - Waiting for process bash with pid 24036
2025-03-09 21:30:55 - DEBUG - Parent: child process of RunExecutor with PID 24036 terminated with return value 0.
2025-03-09 21:30:55 - DEBUG - Process terminated, exit code 0.
2025-03-09 21:30:55 - DEBUG - Cleaning up temporary directory.
$ ls -r output.files/*
'output.files/tmp tmp':
output.files/a:
greetingLet me reconsider, and if you have any advice, please let me know. |
|
Thanks for this contribution! I can confirm what you see so far. The fact that there is no "binding" between The fact that after the run an empty What is a problem, though, is the following: $ mkdir "a" "b"
$ sudo mount --bind "a" "b"
$ touch a/foo
$ ls a b
a:
foo
b:
foo
$ containerexec bash
2025-03-11 08:58:58 - INFO - Starting command bash
benchexec@benchexec:/home/wendler/git/benchexec$ ls a b
a:
foo
b:
benchexec@benchexec:/home/wendler/git/benchexec$ Inside the container Any idea what is going here? Would you like to investigate this? |
|
Thanks for the quick response! I understand what you want containerexec to do. |
|
Here's what I've investigated so far: The OSError discussed in this issue is raised in make_bind_mount(fuse_mount_path, mount_path) with the arguments fuse_mount_path="/tmp/BenchExec_run_xxxxxxxx/fuse_mount/path/to/b", mount_path="/tmp/BenchExec_run_xxxxxxxx/mount/path/to/b", because fuse_mount_path does not exist. However, at the beginning of the loop (see this line), it does exist. When the program executes make_bind_mount(fuse_mount_path, mount_path) with the arguments fuse_mount_path='/tmp/BenchExec_run_xxxxxxxx/overlayfs/fuse_mount/', mount_path='/tmp/BenchExec_run_xxxxxxxx/mount/', it disappears because there is no path/to/b under fuse_mount_path. This issue might be resolved by modifying setup_fuse_overlay(temp_base, work_base) to construct the bind mount from the bottom up. However, in the definition of setup_fuse_overlay(temp_base, work_base), lowerdir is specified as b"/", and I'm unsure how to extract only the bind mount from /proc/self/mounts. This link might be helpful, but I'm not sure if it's the correct approach. |
Thanks!
Hm, I don't understand why
Sorry, I am not really sure what you mean with that? |
Yeah, they are visible. I don't know why, but fuse-overlayfs doesn't properly recognize bind-mounted directories. I made containers/fuse-overlayfs#437, and I'm going to investigate fuse-overlayfs repository further. Here's a simple test code:
Please disregard it. Initially, I assumed that the issue could be resolved by mounting path/to/b/content first, followed by mounting path/to/b. However, this assumption was entirely incorrect. |
Wow, I am surprised.
Yes, with kernel overlayfs one has to replicate every single mount point in the hierarchy. That is something that we do already in BenchExec.
Thanks a lot, I think this is a very well written issue and the best way forward is to wait whether we get a reaction. |
Yeah, it does!
What about directories that are not part of any bind mount? I tried two cases, but neither worked properly:
Do you have any suggestions on how to resolve this issue? |
Hm. Here you would need to use distinct upperdirs and workdirs for each fuse-overlayfs instance (as upperdir we would want to use Then yet another possibility might be to use some fresh directory
Yes, this is how all mounts work. If you mount something on |
|
I tried several approaches and here's what I found so far. fuse-overlayfs with allow_other + mount --bind works fineHere's a successful setup: If we proceed with this method, the users will need to modify the contents of /etc/fuse.conf for setup (man 8 fuse). Below are the unsuccessful attempts.fuse-overlayfs with allow_other + fuse-overlayfs with allow_other didn't work.
I also tried fuse-overlayfs (without allow_other) + fuse-overlayfs (without allow_other) and that didn't work neither.
I attempted this, but it did not work (I'm not sure if I did what was intended). Adding Adding Adding |
Sorry, this is exactly what I don't want the mount to do. |
But this directly mounts
Hm, that would be unfortunate, because it requires root permission at least for installation, and we are happy that most of BenchExec works without that. Also, it seems there is no way to grant this to only a particular user, and system administrators might not always want to give this permission to everyone. But I think I found a solution (more below).
This is also something that I do not understand. If the mount to
I meant this, but with If I try it as you wrote it down and without My understanding is as follows: But if we are in a container, all of the container setup is done by the root user of the container. This means if we first do a fuse-overlayfs mount and then a To try this out we need to enter an interactive container that works the same as BenchExec's container but where we are root. (If we just start # mkdir lowerdir lowerdir/{a,b} updir workdir fuse_mount updir/b workdir_b fuse_mount_b
# mount --bind lowerdir/a lowerdir/b
# touch lowerdir/a/foo
# fuse-overlayfs -o lowerdir=lowerdir,upperdir=updir,workdir=workdir fuse_mount
# ls fuse_mount/*
fuse_mount/a:
foo
fuse_mount/b:
foo
# fuse-overlayfs -o lowerdir=lowerdir/b,upperdir=updir/b,workdir=workdir_b fuse_mount_b
# mount --bind fuse_mount_b fuse_mount/b
# ls fuse_mount/*
fuse_mount/a:
foo
fuse_mount/b:
fooBut I tried further, and now I am even more confused. Because if I try the fuse-overlayfs mount in the container, I even manage to get it working just fine across the bind mount (cf. first I hope it is somewhat clear what I wrote? Can you reproduce this? I think one thing that we can learn is that there are subtle differences between usage of fuse-overlayfs outside of a container as regular user, and inside a container as container root. And we only care about the latter, so we need to try out stuff in the container case. And if my last example works, then there should be in principle a way to make it work in BenchExec as well, because this case is exactly like we want it. |
Sorry, I completely forgot the original intention of creating the container.
Thanks for the detailed explanation. I understand what you’re confused about. On the other hand, if updir/b does not exist before executing the first fuse-overlayfs command, then fuse_mount/b/foo is not present (even inside the container). My guess is as follows: If updir/b does not exist, fuse-overlayfs refers to lowerdir/b but treats it as bodiless and does not handle it as expected. If updir/b exists, fuse-overlayfs recognizes b as a directory and considers its contents from both updir/b/* (empty) and lowerdir/b/* (where foo exists). |
Oh yes, of course. 🤦 It would be interesting to test whether this works as we need, i.e., are writes then sent to And does it also work if we create Because if all of this works, we could get a solution if we just create the necessary Would you like to test this? Your help in this has been invaluable already! |
|
Of course, I'd like to! I'll reply in detail within 24 hours. |
If I write to
If we create |
Wow, also unexpected. Maybe fuse-overlayfs sees that But I guess this would be ok for us. So I think we have something now that could work, and it would be worth to implement it for being able to try it out?
Indeed. |
Yeah, it seems.
I agree! I just created another PR. |
|
Replaced by #1156. |
Contributes to solving the following issue: #1136
The cause of the problem described in the issue is that the source directory is not correctly created when using fuse-overlayfs.