summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/mountpoint-util.c28
-rw-r--r--src/test/test-mountpoint-util.c32
-rw-r--r--src/test/test-path-util.c7
3 files changed, 60 insertions, 7 deletions
diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c
index 8bed96069f..a6602ad539 100644
--- a/src/basic/mountpoint-util.c
+++ b/src/basic/mountpoint-util.c
@@ -132,6 +132,29 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mn
return safe_atoi(p, ret_mnt_id);
}
+static bool filename_possibly_with_slash_suffix(const char *s) {
+ const char *slash, *copied;
+
+ /* Checks whether the specified string is either file name, or a filename with a suffix of
+ * slashes. But nothing else.
+ *
+ * this is OK: foo, bar, foo/, bar/, foo//, bar///
+ * this is not OK: "", "/", "/foo", "foo/bar", ".", ".." … */
+
+ slash = strchr(s, '/');
+ if (!slash)
+ return filename_is_valid(s);
+
+ if (slash - s > FILENAME_MAX) /* We want to allocate on the stack below, hence do a size check first */
+ return false;
+
+ if (slash[strspn(slash, "/")] != 0) /* Check that the suffix consist only of one or more slashes */
+ return false;
+
+ copied = strndupa(s, slash - s);
+ return filename_is_valid(copied);
+}
+
int fd_is_mount_point(int fd, const char *filename, int flags) {
_cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
int mount_id = -1, mount_id_parent = -1;
@@ -144,6 +167,11 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
assert(filename);
assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
+ /* Insist that the specified filename is actually a filename, and not a path, i.e. some inode further
+ * up or down the tree then immediately below the specified directory fd. */
+ if (!filename_possibly_with_slash_suffix(filename))
+ return -EINVAL;
+
/* First we will try statx()' STATX_ATTR_MOUNT_ROOT attribute, which is our ideal API, available
* since kernel 5.8.
*
diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c
index 287488b7c1..47fde5cb2c 100644
--- a/src/test/test-mountpoint-util.c
+++ b/src/test/test-mountpoint-util.c
@@ -256,6 +256,37 @@ static void test_path_is_mount_point(void) {
assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
+static void test_fd_is_mount_point(void) {
+ _cleanup_close_ int fd = -1;
+
+ log_info("/* %s */", __func__);
+
+ fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
+ assert_se(fd >= 0);
+
+ /* Not allowed, since "/" is a path, not a plain filename */
+ assert_se(fd_is_mount_point(fd, "/", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, ".", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "./", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "..", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "../", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "/proc", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "/proc/", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "proc/sys", 0) == -EINVAL);
+ assert_se(fd_is_mount_point(fd, "proc/sys/", 0) == -EINVAL);
+
+ /* This one definitely is a mount point */
+ assert_se(fd_is_mount_point(fd, "proc", 0) > 0);
+ assert_se(fd_is_mount_point(fd, "proc/", 0) > 0);
+
+ /* /root's entire raison d'etre is to be on the root file system (i.e. not in /home/ which might be
+ * split off), so that the user can always log in, so it cannot be a mount point unless the system is
+ * borked. Let's allow for it to be missing though. */
+ assert_se(IN_SET(fd_is_mount_point(fd, "root", 0), -ENOENT, 0));
+ assert_se(IN_SET(fd_is_mount_point(fd, "root/", 0), -ENOENT, 0));
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@@ -279,6 +310,7 @@ int main(int argc, char *argv[]) {
test_mnt_id();
test_path_is_mount_point();
+ test_fd_is_mount_point();
return 0;
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index f4f8d0550b..cb91a1a979 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -6,7 +6,6 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "macro.h"
-#include "mountpoint-util.h"
#include "path-util.h"
#include "rm-rf.h"
#include "stat-util.h"
@@ -40,8 +39,6 @@ static void test_path_simplify(const char *in, const char *out, const char *out_
}
static void test_path(void) {
- _cleanup_close_ int fd = -1;
-
log_info("/* %s */", __func__);
test_path_compare("/goo", "/goo", 0);
@@ -80,10 +77,6 @@ static void test_path(void) {
assert_se(streq(basename("/aa///file..."), "file..."));
assert_se(streq(basename("file.../"), ""));
- fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
- assert_se(fd >= 0);
- assert_se(fd_is_mount_point(fd, "/", 0) > 0);
-
test_path_simplify("aaa/bbb////ccc", "aaa/bbb/ccc", "aaa/bbb/ccc");
test_path_simplify("//aaa/.////ccc", "/aaa/./ccc", "/aaa/ccc");
test_path_simplify("///", "/", "/");