Skip to content

Use mount_setattr() in bind_mount()#756

Open
xxyzz wants to merge 1 commit into
containers:mainfrom
xxyzz:mount_setattr
Open

Use mount_setattr() in bind_mount()#756
xxyzz wants to merge 1 commit into
containers:mainfrom
xxyzz:mount_setattr

Conversation

@xxyzz
Copy link
Copy Markdown

@xxyzz xxyzz commented May 31, 2026

Fix #754, all tests passed. I also update some GitHub Actions.

Comment thread bind-mount.c Outdated
.attr_set = MOUNT_ATTR_NOSUID | (devices ? 0 : MOUNT_ATTR_NODEV) |
(readonly ? MOUNT_ATTR_RDONLY : 0),
};
if (mount_setattr(dest_fd, "",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

musl does not have a library function for mount_setattr yet. Also older (before 2024?) glibc versions. We should ifdef-provide our own definition.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapper function added.

@xxyzz xxyzz force-pushed the mount_setattr branch 2 times, most recently from 69fdb9e to f65b3ec Compare May 31, 2026 08:38
@charmander
Copy link
Copy Markdown

I also update some GitHub Actions.

Were they related somehow?

@xxyzz
Copy link
Copy Markdown
Author

xxyzz commented May 31, 2026

Were they related somehow?

No, these actions are just too outdated so I updated them.

@rusty-snake
Copy link
Copy Markdown
Contributor

What was wrong with has_mount_setattr?

The code changes have some AI smell to me.

@xxyzz
Copy link
Copy Markdown
Author

xxyzz commented Jun 1, 2026

I feel has_mount_setattr is kind of redundant now and the code resembles your previous suggestion in issue 650. I did ask gemini some questions because I'm not sure how to be compatible with musl and the #define lines are modified from the chatbot's answer. Is the change good enough or maybe it need further improvement?

@rusty-snake
Copy link
Copy Markdown
Contributor

Is the change good enough or maybe it need further improvement?

It needs a review from.someone who is actually responsible for the codebase.

@ao2
Copy link
Copy Markdown
Contributor

ao2 commented Jun 2, 2026

I also update some GitHub Actions.

Were they related somehow?

Please move unrelated changes to a separate commit, or even to a separate PR, to have a more focused review, and in general avoid unnecessary space changes.

Also the commit message of the main change should mention the rationale from #754 and also have lines like:

...

Fixes: https://github.com/containers/bubblewrap/issues/754
Signed-off-by: YOUR NAME <email>

Ideally with your real name, but I don't think this is a strict requirement 😄

Comment thread utils.h Outdated
const char *src);

#ifndef __NR_mount_setattr
#define __NR_mount_setattr 442
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that syscall numbers in linux are platform specific, so this is not general enough. E.g. on alpha __NR_mount_setattr is 552, see https://github.com/torvalds/linux/blob/6f3ed7fec72fc8979b2a8c7219c0a9fcfc8d07b5/arch/alpha/kernel/syscalls/syscall.tbl#L484

What about having a simpler approach like done for pivot_root? So that we require that __NR_mount_setattr is defined but we support the cases where the system function mount_setattr is not.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code updated. I think I've read that function before but somehow forgot it...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I like the approach @ao2 suggested here.

This also means that when compiling on ancient kernels, we would have the option to define __NR_mount_setattr on only the architectures that we expect might genuinely be running ancient kernels (in practice usually x86), like this:

#ifndef __NR_mount_setattr
# if defined(__x86_64__)
#   define __NR_mount_setattr ...
# elif defined(__i386__)
#   define __NR_mount_setattr ...
# endif
#endif

bubblewrap is used by Steam Runtime version 1, which is very old, so we should check whether its libc/kernel headers define __NR_mount_setattr. (But that's an easy change to add later; and Steam Runtime v1 only supports x86, so it doesn't have to try to cope with other architectures.)

Copy link
Copy Markdown
Collaborator

@smcv smcv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking at this!

Comment thread bind-mount.c Outdated
break;

case BIND_MOUNT_ERROR_MOUNT_SETATTR:
string = xasprintf("mount_setattr() failed at \"%s\"", failing_path);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: please follow the whitespace style of the existing code, e.g.

Suggested change
string = xasprintf("mount_setattr() failed at \"%s\"", failing_path);
string = xasprintf ("mount_setattr() failed at \"%s\"", failing_path);

Comment thread bind-mount.c Outdated
struct mount_attr attr = {
.attr_clr = 0,
.attr_set = MOUNT_ATTR_NOSUID | (devices ? 0 : MOUNT_ATTR_NODEV) |
(readonly ? MOUNT_ATTR_RDONLY : 0),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be easier to review/analyze if you structured it as an early-return on mount_setattr() success, so that the diff wasn't re-indenting all the code that you're avoiding by using mount_setattr():

  if (mount_setattr_wrapper (...) == 0)
    {
      return BIND_MOUNT_SUCCESS;
    }
  else if (errno != ENOSYS)
    {
      ... report error ...
    }

  /* ... else mount_setattr(2) isn't available, so we'll have to do this the hard way. */

/* If we are in a case-insensitive filesystem, mountinfo might contain a
   * different case combination of the path we requested to mount.
   ...

I haven't reviewed all of the diff here, because at the moment it's hard to tell what is genuinely new or changed code and what is just re-indented.

Comment thread bind-mount.c Outdated
Comment on lines +419 to +420
.attr_set = MOUNT_ATTR_NOSUID | (devices ? 0 : MOUNT_ATTR_NODEV) |
(readonly ? MOUNT_ATTR_RDONLY : 0),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of inline ?: operators, I think this would be easier to read in a structure more like this:

  struct mount_attr attr = {
    .attr_clr = 0,
    .attr_set = MOUNT_ATTR_NOSUID,
};

if (!devices)
  attr.attr_set |= MOUNT_ATTR_NODEV;

if (readonly)
  attr.attr_set |= MOUNT_ATTR_RDONLY;

more like the first commit of #751.

Comment thread bind-mount.c Outdated
(readonly ? MOUNT_ATTR_RDONLY : 0),
};
if (mount_setattr_wrapper (dest_fd, "",
AT_EMPTY_PATH | (recursive ? AT_RECURSIVE : 0), &attr,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly I'd prefer this more like:

unsigned int setattr_flags = AT_EMPTY_PATH;

if (recursive)
  setattr_flags |= AT_RECURSIVE;

...

... mount_setattr_wrapper (dest_fd, "", setattr_flags, ...) ...

Comment thread bind-mount.c Outdated

return BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD;
}
if (errno != ENOSYS)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can mount_setattr() fail with EINVAL if the kernel is new enough to have the syscall, but too old to have one of the flags that we are using?

(It's unfortunate that EINVAL can mean both "you used a flag I didn't understand" and "something about the state of the mount table means I can't carry out your request"...)

Copy link
Copy Markdown
Author

@xxyzz xxyzz Jun 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AT_RECURSIVE was added in 5.2, before mount_setattr added in 5.12. MOUNT_ATTR_NOSYMFOLLOW was added in 5.14 but it's not used. Should be fine.

Comment thread utils.h Outdated
const char *src);

#ifndef __NR_mount_setattr
#define __NR_mount_setattr 442
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I like the approach @ao2 suggested here.

This also means that when compiling on ancient kernels, we would have the option to define __NR_mount_setattr on only the architectures that we expect might genuinely be running ancient kernels (in practice usually x86), like this:

#ifndef __NR_mount_setattr
# if defined(__x86_64__)
#   define __NR_mount_setattr ...
# elif defined(__i386__)
#   define __NR_mount_setattr ...
# endif
#endif

bubblewrap is used by Steam Runtime version 1, which is very old, so we should check whether its libc/kernel headers define __NR_mount_setattr. (But that's an easy change to add later; and Steam Runtime v1 only supports x86, so it doesn't have to try to cope with other architectures.)

@smcv
Copy link
Copy Markdown
Collaborator

smcv commented Jun 2, 2026

[Signed-off-by] Ideally with your real name, but I don't think this is a strict requirement

This was a policy question in the past, and the repo owners concluded that contributions under a pseudonym can be accepted. But...

gitpull at protonmail.com

Is this a real address that is really yours, or a fake/placeholder email address that doesn't really exist?

I think we do need the Signed-off-by to come from an identifiable person, even if they're only identifiable by a pseudonym. Github provides a pseudo-email-address that identifies a Github account which is probably sufficient, although I'd have to check that policy with the repo owners (cc @alexlarsson @cgwalters).

(If this is really your email address then that's fine, it just looks like it might be a placeholder.)

@smcv
Copy link
Copy Markdown
Collaborator

smcv commented Jun 2, 2026

the commit message of the main change should mention the rationale from #754

Yes please. Perhaps something like:

Use mount_setattr() to set mount flags

Unlike the old mount(2) API, this lets us apply the same mount flags recursively to a whole tree of mount points in a single operation, avoiding time-of-check/time-of-use race conditions if the mount table changes (#650) and improving performance when there are many mount points (#384).

... and it can probably have Fixes: https://github.com/containers/bubblewrap/issues/384 and Fixes: https://github.com/containers/bubblewrap/issues/650, if it does in fact fix those issues.

Are you using bubblewrap for something? Does this change solve a problem that you were encountering?

@xxyzz
Copy link
Copy Markdown
Author

xxyzz commented Jun 3, 2026

This is my real email.

I use bwrap indirectly via bubblejail. I don't have any problem with it, I guess the commit probably should fix those linked issues.

Unlike the old mount(2) API, this lets us apply the same mount flags
recursively to a whole tree of mount points in a single operation,
avoiding time-of-check/time-of-use race conditions if the mount table
changes (containers#650) and improving performance when there are many mount
points (containers#384).

Fixes: containers#754

Signed-off-by: xxyzz <gitpull@protonmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use mount_setattr() on newer kernels, instead of walking mount hierarchy the hard way

5 participants