Our baseline on kernel is 5.10, hence we can assume it works.
BPF links and the BPF LSM hook
≥ 5.8 for LOOP_CONFIGURE and STATX_ATTR_MOUNT_ROOT
≥ 5.9 for close_range()
+ ≥ 5.10 for STATX_MNT_ID
⛔ Kernel versions below 5.10 ("minimum baseline") are not supported at all,
and are missing required functionality as listed above.
#include "format-util.h"
#include "fs-util.h"
#include "log.h"
-#include "mountpoint-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
int fds_are_same_mount(int fd1, int fd2) {
struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */
- int r;
assert(fd1 >= 0);
assert(fd2 >= 0);
if (statx(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0)
return -errno;
- /* First, compare inode. If these are different, the fd does not point to the root directory "/". */
- if (!statx_inode_same(&sx1, &sx2))
- return false;
-
- /* Note, statx() does not provide the mount ID and path_get_mnt_id_at() does not work when an old
- * kernel is used. In that case, let's assume that we do not have such spurious mount points in an
- * early boot stage, and silently skip the following check. */
-
- if (!FLAGS_SET(sx1.stx_mask, STATX_MNT_ID)) {
- int mntid;
-
- r = path_get_mnt_id_at_fallback(fd1, "", &mntid);
- if (r < 0)
- return r;
- assert(mntid >= 0);
-
- sx1.stx_mnt_id = mntid;
- sx1.stx_mask |= STATX_MNT_ID;
- }
-
- if (!FLAGS_SET(sx2.stx_mask, STATX_MNT_ID)) {
- int mntid;
-
- r = path_get_mnt_id_at_fallback(fd2, "", &mntid);
- if (r < 0)
- return r;
- assert(mntid >= 0);
-
- sx2.stx_mnt_id = mntid;
- sx2.stx_mask |= STATX_MNT_ID;
- }
-
- return statx_mount_same(&sx1, &sx2);
+ return statx_inode_same(&sx1, &sx2) && statx_mount_same(&sx1, &sx2);
}
char* format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
#include "log.h"
#include "mountpoint-util.h"
#include "nulstr-util.h"
-#include "parse-util.h"
#include "path-util.h"
#include "stat-util.h"
-#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags & ~AT_HANDLE_FID);
}
-static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mnt_id) {
- char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
- _cleanup_close_ int subfd = -EBADF;
- int r;
-
- assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
- assert(ret_mnt_id);
-
- if ((flags & AT_EMPTY_PATH) && isempty(filename))
- xsprintf(path, "/proc/self/fdinfo/%i", fd);
- else {
- subfd = openat(fd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_FOLLOW ? 0 : O_NOFOLLOW));
- if (subfd < 0)
- return -errno;
-
- xsprintf(path, "/proc/self/fdinfo/%i", subfd);
- }
-
- _cleanup_free_ char *p = NULL;
- r = get_proc_field(path, "mnt_id", &p);
- if (r == -ENOENT)
- return -EBADF;
- if (r < 0)
- return r;
-
- return safe_atoi(p, ret_mnt_id);
-}
-
bool file_handle_equal(const struct file_handle *a, const struct file_handle *b) {
if (a == b)
return true;
return is_mount_point_at(dir_fd, /* path= */ NULL, flags);
}
-int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret) {
- int r;
-
- assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
- assert(ret);
-
- r = name_to_handle_at_loop(dir_fd, path, NULL, ret, isempty(path) ? AT_EMPTY_PATH : 0);
- if (r >= 0 || is_name_to_handle_at_fatal_error(r))
- return r;
-
- return fd_fdinfo_mnt_id(dir_fd, path, isempty(path) ? AT_EMPTY_PATH : 0, ret);
-}
-
int path_get_mnt_id_at(int dir_fd, const char *path, int *ret) {
struct statx sx;
+ int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(ret);
&sx) < 0)
return -errno;
- if (FLAGS_SET(sx.stx_mask, STATX_MNT_ID)) {
- *ret = sx.stx_mnt_id;
- return 0;
- }
+ r = statx_warn_mount_id(&sx, LOG_DEBUG);
+ if (r < 0)
+ return r;
- return path_get_mnt_id_at_fallback(dir_fd, path, ret);
+ *ret = sx.stx_mnt_id;
+ return 0;
}
bool fstype_is_network(const char *fstype) {
bool file_handle_equal(const struct file_handle *a, const struct file_handle *b);
-int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret);
int path_get_mnt_id_at(int dir_fd, const char *path, int *ret);
static inline int path_get_mnt_id(const char *path, int *ret) {
return path_get_mnt_id_at(AT_FDCWD, path, ret);
if (!statx_is_set(a) || !statx_is_set(b))
return false;
- /* if we have the mount ID, that's all we need */
- if (FLAGS_SET(a->stx_mask, STATX_MNT_ID) && FLAGS_SET(b->stx_mask, STATX_MNT_ID))
- return a->stx_mnt_id == b->stx_mnt_id;
+ assert(FLAGS_SET(a->stx_mask, STATX_MNT_ID));
+ assert(FLAGS_SET(b->stx_mask, STATX_MNT_ID));
- /* Otherwise, major/minor of backing device must match */
- return a->stx_dev_major == b->stx_dev_major &&
- a->stx_dev_minor == b->stx_dev_minor;
+ return a->stx_mnt_id == b->stx_mnt_id;
}
int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
return 0;
}
+
+int statx_warn_mount_id(const struct statx *sx, int log_level) {
+ assert(sx);
+
+ /* The STATX_MNT_ID flag is supported since kernel v5.10. */
+ if (!FLAGS_SET(sx->stx_mask, STATX_MNT_ID))
+ return log_full_errno(log_level, SYNTHETIC_ERRNO(ENOSYS),
+ "statx() does not support STATX_MNT_ID, running on an old kernel?");
+
+ return 0;
+}
}
int statx_warn_mount_root(const struct statx *sx, int log_level);
+int statx_warn_mount_id(const struct statx *sx, int log_level);