Skip to content

Commit ac2e082

Browse files
committed
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). Fixes: #754 Signed-off-by: Guan Yunpeng <gitpull@protonmail.com>
1 parent 2f55bae commit ac2e082

4 files changed

Lines changed: 77 additions & 0 deletions

File tree

bind-mount.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,36 @@ bind_mount (int proc_fd,
414414
return BIND_MOUNT_ERROR_REOPEN_DEST;
415415
}
416416

417+
struct mount_attr attr = {
418+
.attr_clr = 0,
419+
.attr_set = MOUNT_ATTR_NOSUID,
420+
};
421+
422+
if (!devices)
423+
attr.attr_set |= MOUNT_ATTR_NODEV;
424+
425+
if (readonly)
426+
attr.attr_set |= MOUNT_ATTR_RDONLY;
427+
428+
unsigned int setattr_flags = AT_EMPTY_PATH;
429+
430+
if (recursive)
431+
setattr_flags |= AT_RECURSIVE;
432+
433+
if (mount_setattr_wrapper (dest_fd, "", setattr_flags, &attr, sizeof(attr)) == 0)
434+
{
435+
return BIND_MOUNT_SUCCESS;
436+
}
437+
else if (errno != ENOSYS)
438+
{
439+
if (failing_path != NULL)
440+
*failing_path = steal_pointer (&resolved_dest);
441+
442+
return BIND_MOUNT_ERROR_MOUNT_SETATTR;
443+
}
444+
445+
/* mount_setattr(2) isn't available, so we'll have to do this the hard way: */
446+
417447
/* If we are in a case-insensitive filesystem, mountinfo might contain a
418448
* different case combination of the path we requested to mount.
419449
* This is due to the fact that the kernel, as of the beginning of 2021,
@@ -543,6 +573,10 @@ bind_mount_result_to_string (bind_mount_result res,
543573
failing_path);
544574
break;
545575

576+
case BIND_MOUNT_ERROR_MOUNT_SETATTR:
577+
string = xasprintf ("mount_setattr() failed at \"%s\"", failing_path);
578+
break;
579+
546580
case BIND_MOUNT_SUCCESS:
547581
string = xstrdup ("Success");
548582
break;
@@ -596,6 +630,7 @@ die_with_bind_result (bind_mount_result res,
596630
case BIND_MOUNT_ERROR_REOPEN_DEST:
597631
case BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD:
598632
case BIND_MOUNT_ERROR_FIND_DEST_MOUNT:
633+
case BIND_MOUNT_ERROR_MOUNT_SETATTR:
599634
case BIND_MOUNT_SUCCESS:
600635
default:
601636
fprintf (stderr, ": %s", strerror (saved_errno));

bind-mount.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef enum
3838
BIND_MOUNT_ERROR_FIND_DEST_MOUNT,
3939
BIND_MOUNT_ERROR_REMOUNT_DEST,
4040
BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT,
41+
BIND_MOUNT_ERROR_MOUNT_SETATTR,
4142
} bind_mount_result;
4243

4344
bind_mount_result bind_mount (int proc_fd,

utils.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,3 +1083,15 @@ strappend_escape_for_mount_options (StringBuilder *dest, const char *src)
10831083
src++;
10841084
}
10851085
}
1086+
1087+
int
1088+
mount_setattr_wrapper (int dirfd, const char *path, unsigned int flags,
1089+
struct mount_attr *attr, size_t size)
1090+
{
1091+
#ifdef __NR_mount_setattr
1092+
return syscall (__NR_mount_setattr, dirfd, path, flags, attr, size);
1093+
#else
1094+
errno = ENOSYS;
1095+
return -1;
1096+
#endif
1097+
}

utils.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,32 @@ void strappendf (StringBuilder *dest,
215215
...);
216216
void strappend_escape_for_mount_options (StringBuilder *dest,
217217
const char *src);
218+
219+
#ifndef MOUNT_ATTR_RDONLY
220+
struct mount_attr
221+
{
222+
__u64 attr_set;
223+
__u64 attr_clr;
224+
__u64 propagation;
225+
__u64 userns_fd;
226+
};
227+
228+
#define MOUNT_ATTR_RDONLY 0x00000001
229+
#define MOUNT_ATTR_NOSUID 0x00000002
230+
#define MOUNT_ATTR_NODEV 0x00000004
231+
#define MOUNT_ATTR_NOEXEC 0x00000008
232+
#define MOUNT_ATTR__ATIME 0x00000070
233+
#define MOUNT_ATTR_RELATIME 0x00000000
234+
#define MOUNT_ATTR_NOATIME 0x00000010
235+
#define MOUNT_ATTR_STRICTATIME 0x00000020
236+
#define MOUNT_ATTR_NODIRATIME 0x00000080
237+
#define MOUNT_ATTR_IDMAP 0x00100000
238+
#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
239+
#endif
240+
241+
#ifndef AT_RECURSIVE
242+
#define AT_RECURSIVE 0x8000
243+
#endif
244+
245+
int mount_setattr_wrapper (int dirfd, const char *path, unsigned int flags,
246+
struct mount_attr *attr, size_t size);

0 commit comments

Comments
 (0)