linux: restore read-only /sys in the sysfs userns fallback - #2179
Conversation
kolyshkin
left a comment
There was a problem hiding this comment.
Both your commits are missing the subject; please fix
... and DCO ("Signed-off-by:" line), too. |
|
can you try if this is enough for your case? diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c
index e99a53d9..d23f05a6 100644
--- a/src/libcrun/linux.c
+++ b/src/libcrun/linux.c
@@ -1524,6 +1524,8 @@ do_mount (libcrun_container_t *container, const char *source, int targetfd,
}
else
{
+ cleanup_close int sysfd = -1;
+
crun_error_release (err);
if (sys_old_root_fd >= 0)
{
@@ -1538,6 +1540,17 @@ do_mount (libcrun_container_t *container, const char *source, int targetfd,
ret = mount ("/sys", real_target, NULL, MS_BIND | MS_REC, NULL);
if (UNLIKELY (ret < 0))
return crun_make_error (err, errno, "bind mount `/sys` from the host");
+
+ sysfd = open_mount_target (container, target, err);
+ if (UNLIKELY (sysfd < 0))
+ return sysfd;
+
+ ret = do_remount (sysfd, target,
+ MS_REMOUNT | MS_BIND | (mountflags & ~ALL_PROPAGATIONS),
+ NULL, err);
+ if (UNLIKELY (ret < 0))
+ return ret;
}
return do_masked_or_readonly_path (container, "/sys/fs/cgroup", false, false, err);
} |
c364918 to
e81bf8a
Compare
|
Hey @giuseppe @kolyshkin Thanks for looking. @giuseppe Just tried your patch and it doesn't work. One of prerequisites is to have Squashed commits into 1 and added subject. |
|
the DCO test is still failing. Could you please fix the author in the git commit itself?
|
e81bf8a to
381346e
Compare
thanks for trying that. I'd still prefer to keep the fix local to the workaround, does the following patch work better? diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c
index e99a53d9..94166958 100644
--- a/src/libcrun/linux.c
+++ b/src/libcrun/linux.c
@@ -1504,6 +1504,7 @@ do_mount (libcrun_container_t *container, const char *source, int targetfd,
if (ret > 0)
{
cleanup_close int mountfd = -1;
+ cleanup_close int sysfd = -1;
int sys_old_root_fd = get_old_root_fd (get_private_data (container));
if (sys_old_root_fd >= 0)
@@ -1539,6 +1540,17 @@ do_mount (libcrun_container_t *container, const char *source, int targetfd,
if (UNLIKELY (ret < 0))
return crun_make_error (err, errno, "bind mount `/sys` from the host");
}
+
+ sysfd = open_mount_target (container, target, err);
+ if (UNLIKELY (sysfd < 0))
+ return sysfd;
+
+ ret = do_remount (sysfd, target,
+ MS_REMOUNT | MS_BIND | (mountflags & ~ALL_PROPAGATIONS),
+ NULL, err);
+ if (UNLIKELY (ret < 0))
+ return ret;
+
return do_masked_or_readonly_path (container, "/sys/fs/cgroup", false, false, err);
}
@@ -1549,6 +1561,16 @@ do_mount (libcrun_container_t *container, const char *source, int targetfd,
if (UNLIKELY (ret < 0))
return crun_make_error (err, errno, "move mount to `%s`", real_target);
+ sysfd = open_mount_target (container, target, err);
+ if (UNLIKELY (sysfd < 0))
+ return sysfd;
+
+ ret = do_remount (sysfd, target,
+ MS_REMOUNT | MS_BIND | (mountflags & ~ALL_PROPAGATIONS),
+ NULL, err);
+ if (UNLIKELY (ret < 0))
+ return ret;
+
return 0;
}
}if it does work for you, just amend it in your commit and keep the test as it is |
381346e to
a4bb84b
Compare
|
@giuseppe Seems to be working, thanks for quick reaction and help. |
|
there is a test failing locally, are you ok if I push any fix to your branch? |
|
Sure, feel free to push |
|
@giuseppe I've also noticed /dev/{null,zero,full,tty,random,urandom} also lose their noexec flag on 1.29 when the container has a user namespace (1.28: rw,nosuid,noexec; 1.29: rw,nosuid). Could you please clarify if it's expected or should I file separate issue for it? |
isn't that just "aesthetic"? Is it a real problem? |
|
I'm not sure if it's a problem (probably not). I've discovered it the same way a discovered initial problem (mounts diff between versions) so decided to double check if it's expected. |
Rename has_mount_for to find_mount_for and return the mount struct (or NULL) instead of a bool, so callers can inspect the matched mount's options. No functional change. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Apply MS_NOSUID | MS_NOEXEC to the cloned mount before moving it, as the other code paths already do, and fall back to recreating the mount from scratch if that fails. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
a4bb84b to
b1e7b85
Compare
|
@dmytrobe let me know if you are ok with the last version |
When a container has a user namespace but does not own the network namespace, creating a fresh sysfs fails with EPERM and do_mount() falls back to bind-mounting the host's /sys instead. That fallback only runs because MS_RDONLY was requested, so the result has to stay read-only. 9259e89 ("use new mount API in do_mount when available", 1.29) rewrote this fallback around get_bind_mount()/fs_move_mount_to() but never re-applies MS_RDONLY along either of its two success paths, so a spec asking for a read-only /sys silently got a writable one instead: crun 1.28 /sys = ro,nosuid,nodev,noexec,relatime crun 1.29 /sys = rw,nosuid,nodev,noexec,relatime After moving or bind-mounting /sys into place, explicitly remount it with the container's requested mount flags (MS_RDONLY included, via mountflags & ~ALL_PROPAGATIONS) at both call sites. This keeps the fix local to the fallback instead of changing what get_bind_mount() itself requests. Extend mount-ro-cgroup in tests/test_mounts.py with a userns axis and an assertion on /sys's own mount flags (it previously only asserted /sys/fs/cgroup). Without a userns the fallback path was never reached, so the regression went uncovered. Verified against crun built from the 1.28 and 1.29 tags: both fail, each in the branch its own bug lives in; this fix passes all 16 combinations, and mount-ro-cgroup passes in the full test_mounts.py suite. Fixes: containers#2178 Signed-off-by: Dmytro Bieliaiev <dimabelyaev27@gmail.com>
|
Great that it fixes both issues. I only see some linter failure but apart from that LGTM. |
b1e7b85 to
18505f0
Compare
Extract the /sys bind-mount workaround used when creating a fresh sysfs mount fails in a user namespace into a dedicated function. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
When do_mount() reopens the target after the mount (because the previous
targetfd ends up shadowed underneath the new mountpoint), real_target was
left pointing at the old, now-shadowed /proc/self/fd/<fd> path.
On kernels that provide mount_setattr() (>= 5.12) this is harmless: the
propagation and remount steps operate on the reopened targetfd. On older
kernels the code falls back to the classic mount(2) API, which uses
real_target, and the shadowed path is no longer a mountpoint, so setting
the propagation fails with EINVAL:
set propagation for `etc/hosts`: Invalid argument
Restore the real_target refresh that used to follow the reopen (dropped in
commit 5506b6e) so the mount(2) fallbacks act on the reopened mountpoint.
Fixes: containers#2182
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
|
Re |
Related to #2178.
Since 1.29,
/syscan end up mounted read-write even though the spec requests it read-only (type: sysfs,"ro").This happens when a container's user namespace doesn't own its network namespace: creating a fresh sysfs then fails, so crun falls back to bind-mounting the host's
/sysinstead. If the spec also has a/sys/fs/cgroupmount, that fallback drops theroflag.The root cause is a
get_bind_mount()call indo_mount(). 9259e891a split it from one call into two and passedrdonly=falseto both, even though this fallback exists specifically to preserve a read-only mount. This PR restoresrdonly=true.Also extends
mount-ro-cgroupwith ausernsaxis and a/sysread-only assertion — it fails on both 1.28 and 1.29, passes with this change.I'm not fully confident this is the right fix: it also makes the no-
/sys/fs/cgroup-mount case read-only, which was already broken on 1.28 too, so it goes a little beyond a minimal regression fix.