Commit 5990b5d7 authored by Christian Brauner's avatar Christian Brauner

tests: test MOUNT_ATTR_NOSYMFOLLOW with mount_setattr()

Add tests to verify that MOUNT_ATTR_NOSYMFOLLOW is honored.

Cc: Christoph Hellwig <hch@lst.de>
Cc: Mattias Nissler <mnissler@chromium.org>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Ross Zwisler <zwisler@google.com>
Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
parent dd8b477f
...@@ -136,6 +136,10 @@ struct mount_attr { ...@@ -136,6 +136,10 @@ struct mount_attr {
#define MOUNT_ATTR_IDMAP 0x00100000 #define MOUNT_ATTR_IDMAP 0x00100000
#endif #endif
#ifndef MOUNT_ATTR_NOSYMFOLLOW
#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
#endif
static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags, static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags,
struct mount_attr *attr, size_t size) struct mount_attr *attr, size_t size)
{ {
...@@ -235,6 +239,10 @@ static int prepare_unpriv_mountns(void) ...@@ -235,6 +239,10 @@ static int prepare_unpriv_mountns(void)
return 0; return 0;
} }
#ifndef ST_NOSYMFOLLOW
#define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */
#endif
static int read_mnt_flags(const char *path) static int read_mnt_flags(const char *path)
{ {
int ret; int ret;
...@@ -245,9 +253,9 @@ static int read_mnt_flags(const char *path) ...@@ -245,9 +253,9 @@ static int read_mnt_flags(const char *path)
if (ret != 0) if (ret != 0)
return -EINVAL; return -EINVAL;
if (stat.f_flag & if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC |
~(ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC | ST_NOATIME | ST_NOATIME | ST_NODIRATIME | ST_RELATIME |
ST_NODIRATIME | ST_RELATIME | ST_SYNCHRONOUS | ST_MANDLOCK)) ST_SYNCHRONOUS | ST_MANDLOCK | ST_NOSYMFOLLOW))
return -EINVAL; return -EINVAL;
mnt_flags = 0; mnt_flags = 0;
...@@ -269,6 +277,8 @@ static int read_mnt_flags(const char *path) ...@@ -269,6 +277,8 @@ static int read_mnt_flags(const char *path)
mnt_flags |= MS_SYNCHRONOUS; mnt_flags |= MS_SYNCHRONOUS;
if (stat.f_flag & ST_MANDLOCK) if (stat.f_flag & ST_MANDLOCK)
mnt_flags |= ST_MANDLOCK; mnt_flags |= ST_MANDLOCK;
if (stat.f_flag & ST_NOSYMFOLLOW)
mnt_flags |= ST_NOSYMFOLLOW;
return mnt_flags; return mnt_flags;
} }
...@@ -368,8 +378,13 @@ static bool mount_setattr_supported(void) ...@@ -368,8 +378,13 @@ static bool mount_setattr_supported(void)
FIXTURE(mount_setattr) { FIXTURE(mount_setattr) {
}; };
#define NOSYMFOLLOW_TARGET "/mnt/A/AA/data"
#define NOSYMFOLLOW_SYMLINK "/mnt/A/AA/symlink"
FIXTURE_SETUP(mount_setattr) FIXTURE_SETUP(mount_setattr)
{ {
int fd = -EBADF;
if (!mount_setattr_supported()) if (!mount_setattr_supported())
SKIP(return, "mount_setattr syscall not supported"); SKIP(return, "mount_setattr syscall not supported");
...@@ -412,6 +427,11 @@ FIXTURE_SETUP(mount_setattr) ...@@ -412,6 +427,11 @@ FIXTURE_SETUP(mount_setattr)
ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts", ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts",
MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0); MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0);
fd = creat(NOSYMFOLLOW_TARGET, O_RDWR | O_CLOEXEC);
ASSERT_GT(fd, 0);
ASSERT_EQ(symlink(NOSYMFOLLOW_TARGET, NOSYMFOLLOW_SYMLINK), 0);
ASSERT_EQ(close(fd), 0);
} }
FIXTURE_TEARDOWN(mount_setattr) FIXTURE_TEARDOWN(mount_setattr)
...@@ -1421,4 +1441,66 @@ TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid) ...@@ -1421,4 +1441,66 @@ TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid)
ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0); ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0);
} }
TEST_F(mount_setattr, mount_attr_nosymfollow)
{
int fd;
unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
struct mount_attr attr = {
.attr_set = MOUNT_ATTR_NOSYMFOLLOW,
};
if (!mount_setattr_supported())
SKIP(return, "mount_setattr syscall not supported");
fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
ASSERT_GT(fd, 0);
ASSERT_EQ(close(fd), 0);
old_flags = read_mnt_flags("/mnt/A");
ASSERT_GT(old_flags, 0);
ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
expected_flags = old_flags;
expected_flags |= ST_NOSYMFOLLOW;
new_flags = read_mnt_flags("/mnt/A");
ASSERT_EQ(new_flags, expected_flags);
new_flags = read_mnt_flags("/mnt/A/AA");
ASSERT_EQ(new_flags, expected_flags);
new_flags = read_mnt_flags("/mnt/A/AA/B");
ASSERT_EQ(new_flags, expected_flags);
new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
ASSERT_EQ(new_flags, expected_flags);
fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
ASSERT_LT(fd, 0);
ASSERT_EQ(errno, ELOOP);
attr.attr_set &= ~MOUNT_ATTR_NOSYMFOLLOW;
attr.attr_clr |= MOUNT_ATTR_NOSYMFOLLOW;
ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
expected_flags &= ~ST_NOSYMFOLLOW;
new_flags = read_mnt_flags("/mnt/A");
ASSERT_EQ(new_flags, expected_flags);
new_flags = read_mnt_flags("/mnt/A/AA");
ASSERT_EQ(new_flags, expected_flags);
new_flags = read_mnt_flags("/mnt/A/AA/B");
ASSERT_EQ(new_flags, expected_flags);
new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
ASSERT_EQ(new_flags, expected_flags);
fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
ASSERT_GT(fd, 0);
ASSERT_EQ(close(fd), 0);
}
TEST_HARNESS_MAIN TEST_HARNESS_MAIN
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment