Don't require mount point for a non-directory to be a regular file

Previously, mounting a socket over the top of an existing socket
would fail, because create_file() opens it with creat():

    $ test -e /run/systemd/resolve/io.systemd.Resolve && echo exists
    exists
    $ bwrap \
      --bind / / \
      --bind /run/systemd/resolve/io.systemd.Resolve \
             /run/systemd/resolve/io.systemd.Resolve \
      /bin/true
    bwrap: Can't create file at /run/systemd/resolve/io.systemd.Resolve: No such device or address

Tolerate the file existing as any type that we will be able to mount
a non-directory onto.

Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie
2021-03-11 19:52:28 +00:00
parent dc4c266cc5
commit a00f39fc4e
2 changed files with 15 additions and 3 deletions

View File

@@ -80,7 +80,7 @@ if [ -z "${BWRAP_MUST_WORK-}" ] && ! $RUN true; then
skip Seems like bwrap is not working at all. Maybe setuid is not working skip Seems like bwrap is not working at all. Maybe setuid is not working
fi fi
echo "1..50" echo "1..51"
# Test help # Test help
${BWRAP} --help > help.txt ${BWRAP} --help > help.txt
@@ -398,4 +398,11 @@ command stat -c '%a' new-file-mountpoint > new-file-permissions
assert_file_has_content new-file-permissions 444 assert_file_has_content new-file-permissions 444
echo "ok - Files and directories created as mount points have expected permissions" echo "ok - Files and directories created as mount points have expected permissions"
if [ -S /dev/log ]; then
$RUN --bind / / --bind "$(realpath /dev/log)" "$(realpath /dev/log)" true
echo "ok - Can bind-mount a socket (/dev/log) onto a socket"
else
echo "ok # SKIP - /dev/log is not a socket, cannot test bubblewrap#409"
fi
echo "ok - End of test" echo "ok - End of test"

View File

@@ -448,9 +448,14 @@ ensure_file (const char *path,
/* We check this ahead of time, otherwise /* We check this ahead of time, otherwise
the create file will fail in the read-only the create file will fail in the read-only
case with EROFS instead of EEXIST */ case with EROFS instead of EEXIST.
We're trying to set up a mount point for a non-directory, so any
non-directory, non-symlink is acceptable - it doesn't necessarily
have to be a regular file. */
if (stat (path, &buf) == 0 && if (stat (path, &buf) == 0 &&
S_ISREG (buf.st_mode)) !S_ISDIR (buf.st_mode) &&
!S_ISLNK (buf.st_mode))
return 0; return 0;
if (create_file (path, mode, NULL) != 0 && errno != EEXIST) if (create_file (path, mode, NULL) != 0 && errno != EEXIST)