libct/specconv: always clear entire MOUNT_ATTR__ATIME field when updating atime mode#5098
Conversation
ba23bec to
ec9676f
Compare
There was a problem hiding this comment.
Pull request overview
This pull request fixes a bug where recursive mount operations with access-time settings (like ratime, rnostrictatime) would fail with EINVAL. The issue occurred because the code was setting partial ATIME masks in the attr_clr field of mount_setattr(2), violating the kernel requirement that the entire MOUNT_ATTR__ATIME mask must be specified when modifying any atime-related attribute.
Changes:
- Modified
parseMountOptionsto ensureMOUNT_ATTR__ATIMEis always included inattr_clrwhen any atime flag is processed, regardless of whether it's being set or cleared - Added comprehensive integration test coverage for all six recursive atime mount options
- Changed test setup from
setup_busyboxtosetup_debianto use thefindmntcommand for verifying mount options
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| libcontainer/specconv/spec_linux.go | Moved the MOUNT_ATTR__ATIME check outside the else block so it applies to both set and clear operations, ensuring the full atime mask is always included in attr_clr |
| tests/integration/mounts_recursive.bats | Changed from busybox to debian image for findmnt support, and added comprehensive test for all recursive atime mount options (ratime, rnoatime, rstrictatime, rnostrictatime, rrelatime, rnorelatime) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@saku3 PTAL |
| update_config ".mounts += [{source: \"${TESTVOLUME}\" , destination: \"/mnt3\", options: [\"rbind\",\"rstrictatime\"]}]" | ||
| update_config ".mounts += [{source: \"${TESTVOLUME}\" , destination: \"/mnt4\", options: [\"rbind\",\"rnostrictatime\"]}]" | ||
| update_config ".mounts += [{source: \"${TESTVOLUME}\" , destination: \"/mnt5\", options: [\"rbind\",\"rrelatime\"]}]" | ||
| update_config ".mounts += [{source: \"${TESTVOLUME}\" , destination: \"/mnt6\", options: [\"rbind\",\"rnorelatime\"]}]" |
There was a problem hiding this comment.
I got stuck on this part.
When specifying rnorelatime, it maps to unix.MOUNT_ATTR_RELATIME, but MOUNT_ATTR_RELATIME is defined as 0x0. As a result, recAttrSet &= ^f.flag becomes recAttrSet &= ^0, which is effectively a no-op.
This seems incorrect from a specification point of view.
rnorelatime is the recursive form of norelatime, and according to mount(8):
norelatime: Do not use the relatime feature. See also the strictatime mount option.
Personally, I think it would be more consistent to map rnorelatime to MOUNT_ATTR_STRICTATIME, e.g.:
"rnorelatime": {false, unix.MOUNT_ATTR_STRICTATIME}
so that rnorelatime recursively enforces strictatime.
There was a problem hiding this comment.
I had the same thought. My integration test shows rnorelatime and rrelatime are functionally equivalent here. You're right. WDYT @cyphar
There was a problem hiding this comment.
You are overthinking it. The "norelatime" attribute just removes the "MS_RELATIME" if it is previously set. An example is, there is an entry in /etc/fstab that has relatime option, and then you use mount(8) command with -o norelatime option for the same destination.
In any case, it should NOT set strictatime.
Since we only have 1 source of mount options in runc (unlike mount which reads fstab first and then command line options), norelatime should probably be a no-op (unless relatime is specified earlier, in which case it should merely remove the MS_RELATIME flag).
There was a problem hiding this comment.
I would also suggest not overthinking it. When I redid the mount flags a while ago I hit the RELATIME-is-now-default (and mount(2) flags for atime are even more confusing). norelatime is a no-op because it became the default and atime mount flags were pretty sctrwed up on Linux as a result. If a user wants strictatime they should set it explicitly, and we should not do any more magic.
There was a problem hiding this comment.
Thank you for the explanation. I understand now.
I’m OK with this change.
Thanks again for making the fix.
There was a problem hiding this comment.
To confirm: the intent is that norelatime is a no-op, not an alias for strictatime, and the patch reflects that.
Thanks for the discussion, @saku3 .
kolyshkin
left a comment
There was a problem hiding this comment.
Just a nit @lifubang: by putting the test commit first, you're breaking git bisect. The commit with the fix should come first, then the commit with the test case. Or, feel free to squash them together since there is not too much code and they are closely related.
When parsing mount options into recAttrSet and recAttrClr, the code sets attr_clr to individual atime flags (e.g. MOUNT_ATTR_NOATIME or MOUNT_ATTR_STRICTATIME) when clearing atime attributes. However, this violates the kernel's requirement documented in mount_setattr(2)[1]: > Note that, since the access-time values are an enumeration > rather than bit values, a caller wanting to transition to a > different access-time setting cannot simply specify the > access-time setting in attr_set, but must also include > MOUNT_ATTR__ATIME in the attr_clr field. The kernel will > verify that MOUNT_ATTR__ATIME isn't partially set in > attr_clr (i.e., either all bits in the MOUNT_ATTR__ATIME > bit field are either set or clear), and that attr_set > doesn't have any access-time bits set if MOUNT_ATTR__ATIME > isn't set in attr_clr. Passing only a single atime flag (e.g. MOUNT_ATTR_RELATIME) in attr_clr causes mount_setattr() to fail with EINVAL. This change ensures that whenever an atime mode is updated, attr_clr includes MOUNT_ATTR__ATIME to properly reset the entire access-time attribute field before applying the new mode. [1] https://man7.org/linux/man-pages/man2/mount_setattr.2.html Signed-off-by: lifubang <lifubang@acmcoder.com>
ec9676f to
5560d55
Compare
You're right — I originally wrote the test case first to reproduce the issue in runc, but I forgot to reorder the commits. I've now squashed them together appropriately. |
|
This is a long-standing bug — would it make sense to backport the fix to release-1.3 and release-1.2? |
|
To release-1.3, sure. For release-1.2 we should only really be doing security backports at this point (and it will stop being supported in April). |
|
@lifubang can you please open the backports? |
Fix #5095
Close #5096
When parsing mount options into recAttrSet and recAttrClr,
the code sets attr_clr to individual atime flags (e.g.
MOUNT_ATTR_NOATIME or MOUNT_ATTR_STRICTATIME) when clearing
atime attributes. However, this violates the kernel's
requirement documented in mount_setattr(2)[1]:
Passing only a single atime flag (e.g. MOUNT_ATTR_RELATIME) in
attr_clr causes mount_setattr() to fail with EINVAL.
This change ensures that whenever an atime mode is updated,
attr_clr includes MOUNT_ATTR__ATIME to properly reset the
entire access-time attribute field before applying the new mode.
[1] https://man7.org/linux/man-pages/man2/mount_setattr.2.html
Signed-off-by: lifubang lifubang@acmcoder.com