diff --git a/bind-mount.c b/bind-mount.c index a7a729dd..609e6508 100644 --- a/bind-mount.c +++ b/bind-mount.c @@ -414,6 +414,36 @@ bind_mount (int proc_fd, return BIND_MOUNT_ERROR_REOPEN_DEST; } + 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; + + unsigned int setattr_flags = AT_EMPTY_PATH; + + if (recursive) + setattr_flags |= AT_RECURSIVE; + + if (mount_setattr_wrapper (dest_fd, "", setattr_flags, &attr, sizeof(attr)) == 0) + { + return BIND_MOUNT_SUCCESS; + } + else if (errno != ENOSYS) + { + if (failing_path != NULL) + *failing_path = steal_pointer (&resolved_dest); + + return BIND_MOUNT_ERROR_MOUNT_SETATTR; + } + + /* 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. * 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, failing_path); break; + case BIND_MOUNT_ERROR_MOUNT_SETATTR: + string = xasprintf ("mount_setattr() failed at \"%s\"", failing_path); + break; + case BIND_MOUNT_SUCCESS: string = xstrdup ("Success"); break; @@ -596,6 +630,7 @@ die_with_bind_result (bind_mount_result res, case BIND_MOUNT_ERROR_REOPEN_DEST: case BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD: case BIND_MOUNT_ERROR_FIND_DEST_MOUNT: + case BIND_MOUNT_ERROR_MOUNT_SETATTR: case BIND_MOUNT_SUCCESS: default: fprintf (stderr, ": %s", strerror (saved_errno)); diff --git a/bind-mount.h b/bind-mount.h index 8f2d5108..bcfa87aa 100644 --- a/bind-mount.h +++ b/bind-mount.h @@ -38,6 +38,7 @@ typedef enum BIND_MOUNT_ERROR_FIND_DEST_MOUNT, BIND_MOUNT_ERROR_REMOUNT_DEST, BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT, + BIND_MOUNT_ERROR_MOUNT_SETATTR, } bind_mount_result; bind_mount_result bind_mount (int proc_fd, diff --git a/utils.c b/utils.c index 55a7f5b1..b60d792a 100644 --- a/utils.c +++ b/utils.c @@ -1083,3 +1083,15 @@ strappend_escape_for_mount_options (StringBuilder *dest, const char *src) src++; } } + +int +mount_setattr_wrapper (int dirfd, const char *path, unsigned int flags, + struct mount_attr *attr, size_t size) +{ +#ifdef __NR_mount_setattr + return syscall (__NR_mount_setattr, dirfd, path, flags, attr, size); +#else + errno = ENOSYS; + return -1; +#endif +} diff --git a/utils.h b/utils.h index 079fe7c9..990c59a9 100644 --- a/utils.h +++ b/utils.h @@ -215,3 +215,32 @@ void strappendf (StringBuilder *dest, ...); void strappend_escape_for_mount_options (StringBuilder *dest, const char *src); + +#ifndef MOUNT_ATTR_RDONLY +struct mount_attr +{ + __u64 attr_set; + __u64 attr_clr; + __u64 propagation; + __u64 userns_fd; +}; + +#define MOUNT_ATTR_RDONLY 0x00000001 +#define MOUNT_ATTR_NOSUID 0x00000002 +#define MOUNT_ATTR_NODEV 0x00000004 +#define MOUNT_ATTR_NOEXEC 0x00000008 +#define MOUNT_ATTR__ATIME 0x00000070 +#define MOUNT_ATTR_RELATIME 0x00000000 +#define MOUNT_ATTR_NOATIME 0x00000010 +#define MOUNT_ATTR_STRICTATIME 0x00000020 +#define MOUNT_ATTR_NODIRATIME 0x00000080 +#define MOUNT_ATTR_IDMAP 0x00100000 +#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 +#endif + +#ifndef AT_RECURSIVE +#define AT_RECURSIVE 0x8000 +#endif + +int mount_setattr_wrapper (int dirfd, const char *path, unsigned int flags, + struct mount_attr *attr, size_t size);