mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
generic: add fstests for idmapped mounts
Add a test suite to verify the behavior of idmapped mounts. The test
suite also includes a range of vfs tests to verify that no regressions
are introduced by idmapped mounts. The following tests are currently
available with more to come in the future:
01. posix acls on regular and idmapped mounts
02. create operations in user namespace
03. device node creation in user namespace
04. expected ownership on idmapped mounts
05. fscaps on regular mounts
06. fscaps on idmapped mounts
07. fscaps on idmapped mounts in user namespace
08. fscaps on idmapped mounts in user namespace
with different id mappings
09. mapped fsids
10. unmapped fsids
11. cross mount hardlink
12. cross idmapped mount hardlink
13. hardlinks from idmapped mounts
14. hardlinks from idmapped mounts in user namespace
15. io_uring
16. io_uring in user namespace
17. io_uring from idmapped mounts
18. io_uring from idmapped mounts in user namespace
19. io_uring from idmapped mounts with unmapped ids
20. io_uring from idmapped mounts with unmapped ids in user namespace
21. following protected symlinks on regular mounts
22. following protected symlinks on idmapped mounts
23. following protected symlinks on idmapped mounts in user namespace
24. cross mount rename
25. cross idmapped mount rename
26. rename from idmapped mounts
27. rename from idmapped mounts in user namespace
28. symlink from regular mounts
29. symlink from idmapped mounts
30. symlink from idmapped mounts in user namespace
31. setid binaries on regular mounts
32. setid binaries on idmapped mounts
33. setid binaries on idmapped mounts in user namespace
34. setid binaries on idmapped mounts in user namespace
with different id mappings
35. sticky bit unlink operations on regular mounts
36. sticky bit unlink operations on idmapped mounts
37. sticky bit unlink operations on idmapped mounts in user namespace
38. sticky bit rename operations on regular mounts
39. sticky bit rename operations on idmapped mounts
40. sticky bit rename operations on idmapped mounts in user namespace
41. create operations in directories with setgid bit set
42. create operations in directories with setgid bit set
on idmapped mounts
43. create operations in directories with setgid bit set
on idmapped mounts in user namespace
44. verify create operations and ownership with racing threads idmapping
a mount
45. setattr truncate operations on regular mounts
46. setattr truncate operations on idmapped mounts
47. setattr truncate operations on idmapped mounts in user namespace
Here's some sample output when running with DEBUG_TRACE defined:
Cc: Amir Goldstein <amir73il@gmail.com>
Cc: Eryu Guan <guan@eryu.me>
Cc: fstests@vger.kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
This commit is contained in:
committed by
Eryu Guan
parent
a7f90c1433
commit
0d1af68e1a
@@ -178,6 +178,7 @@
|
|||||||
/src/aio-dio-regress/aio-last-ref-held-by-io
|
/src/aio-dio-regress/aio-last-ref-held-by-io
|
||||||
/src/aio-dio-regress/aiocp
|
/src/aio-dio-regress/aiocp
|
||||||
/src/aio-dio-regress/aiodio_sparse2
|
/src/aio-dio-regress/aiodio_sparse2
|
||||||
|
/src/idmapped-mounts/idmapped-mounts
|
||||||
/src/log-writes/replay-log
|
/src/log-writes/replay-log
|
||||||
/src/perf/*.pyc
|
/src/perf/*.pyc
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ _______________________
|
|||||||
sudo apt-get install xfslibs-dev uuid-dev libtool-bin \
|
sudo apt-get install xfslibs-dev uuid-dev libtool-bin \
|
||||||
e2fsprogs automake gcc libuuid1 quota attr make \
|
e2fsprogs automake gcc libuuid1 quota attr make \
|
||||||
libacl1-dev libaio-dev xfsprogs libgdbm-dev gawk fio dbench \
|
libacl1-dev libaio-dev xfsprogs libgdbm-dev gawk fio dbench \
|
||||||
uuid-runtime python sqlite3 liburing-dev
|
uuid-runtime python sqlite3 liburing-dev libcap-dev
|
||||||
For Fedora, RHEL, or CentOS:
|
For Fedora, RHEL, or CentOS:
|
||||||
yum install acl attr automake bc dbench dump e2fsprogs fio \
|
yum install acl attr automake bc dbench dump e2fsprogs fio \
|
||||||
gawk gcc indent libtool lvm2 make psmisc quota sed \
|
gawk gcc indent libtool lvm2 make psmisc quota sed \
|
||||||
xfsdump xfsprogs \
|
xfsdump xfsprogs \
|
||||||
libacl-devel libaio-devel libuuid-devel \
|
libacl-devel libaio-devel libuuid-devel \
|
||||||
xfsprogs-devel btrfs-progs-devel python sqlite liburing-devel
|
xfsprogs-devel btrfs-progs-devel python sqlite liburing-devel \
|
||||||
|
libcap-devel
|
||||||
(Older distributions may require xfsprogs-qa-devel as well.)
|
(Older distributions may require xfsprogs-qa-devel as well.)
|
||||||
(Note that for RHEL and CentOS, you may need the EPEL repo.)
|
(Note that for RHEL and CentOS, you may need the EPEL repo.)
|
||||||
- run make
|
- run make
|
||||||
|
|||||||
@@ -1980,6 +1980,40 @@ _require_io_uring()
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# test whether the mount_setattr syscall is available
|
||||||
|
_require_mount_setattr()
|
||||||
|
{
|
||||||
|
$here/src/feature -r
|
||||||
|
case $? in
|
||||||
|
0)
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
_notrun "kernel does not support mount_setattr syscall"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_fail "unexpected error testing for mount_setattr support"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# test whether idmapped mounts are supported
|
||||||
|
_require_idmapped_mounts()
|
||||||
|
{
|
||||||
|
IDMAPPED_MOUNTS_TEST=$here/src/idmapped-mounts/idmapped-mounts
|
||||||
|
[ -x $IDMAPPED_MOUNTS_TEST ] || _notrun "idmapped-mounts utilities required"
|
||||||
|
|
||||||
|
_require_mount_setattr
|
||||||
|
|
||||||
|
$here/src/idmapped-mounts/idmapped-mounts --supported \
|
||||||
|
--device "$TEST_DEV" \
|
||||||
|
--mount "$TEST_DIR" \
|
||||||
|
--fstype "$FSTYP"
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
_notrun "idmapped-mounts not support by $FSTYP"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# this test requires that a test program exists under src/
|
# this test requires that a test program exists under src/
|
||||||
# $1 - command (require)
|
# $1 - command (require)
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ AC_PACKAGE_NEED_ACLINIT_LIBACL
|
|||||||
AC_PACKAGE_WANT_GDBM
|
AC_PACKAGE_WANT_GDBM
|
||||||
AC_PACKAGE_WANT_AIO
|
AC_PACKAGE_WANT_AIO
|
||||||
AC_PACKAGE_WANT_URING
|
AC_PACKAGE_WANT_URING
|
||||||
|
AC_PACKAGE_WANT_LIBCAP
|
||||||
AC_PACKAGE_WANT_LINUX_FIEMAP_H
|
AC_PACKAGE_WANT_LINUX_FIEMAP_H
|
||||||
AC_PACKAGE_WANT_FALLOCATE
|
AC_PACKAGE_WANT_FALLOCATE
|
||||||
AC_PACKAGE_WANT_OPEN_BY_HANDLE_AT
|
AC_PACKAGE_WANT_OPEN_BY_HANDLE_AT
|
||||||
@@ -68,6 +69,7 @@ AC_PACKAGE_WANT_LIBBTRFSUTIL
|
|||||||
AC_HAVE_COPY_FILE_RANGE
|
AC_HAVE_COPY_FILE_RANGE
|
||||||
|
|
||||||
AC_CHECK_FUNCS([renameat2])
|
AC_CHECK_FUNCS([renameat2])
|
||||||
|
AC_CHECK_TYPES([struct mount_attr], [], [], [[#include <linux/mount.h>]])
|
||||||
|
|
||||||
AC_CONFIG_HEADER(include/config.h)
|
AC_CONFIG_HEADER(include/config.h)
|
||||||
AC_CONFIG_FILES([include/builddefs])
|
AC_CONFIG_FILES([include/builddefs])
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ ENABLE_SHARED = @enable_shared@
|
|||||||
HAVE_DB = @have_db@
|
HAVE_DB = @have_db@
|
||||||
HAVE_AIO = @have_aio@
|
HAVE_AIO = @have_aio@
|
||||||
HAVE_URING = @have_uring@
|
HAVE_URING = @have_uring@
|
||||||
|
HAVE_LIBCAP = @have_libcap@
|
||||||
HAVE_FALLOCATE = @have_fallocate@
|
HAVE_FALLOCATE = @have_fallocate@
|
||||||
HAVE_OPEN_BY_HANDLE_AT = @have_open_by_handle_at@
|
HAVE_OPEN_BY_HANDLE_AT = @have_open_by_handle_at@
|
||||||
HAVE_FIEMAP = @have_fiemap@
|
HAVE_FIEMAP = @have_fiemap@
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ LSRCFILES = \
|
|||||||
package_aiodev.m4 \
|
package_aiodev.m4 \
|
||||||
package_gdbmdev.m4 \
|
package_gdbmdev.m4 \
|
||||||
package_globals.m4 \
|
package_globals.m4 \
|
||||||
|
package_libcap.m4 \
|
||||||
package_libcdev.m4 \
|
package_libcdev.m4 \
|
||||||
package_liburing.m4 \
|
package_liburing.m4 \
|
||||||
package_ncurses.m4 \
|
package_ncurses.m4 \
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
AC_DEFUN([AC_PACKAGE_WANT_LIBCAP],
|
||||||
|
[ AC_CHECK_HEADERS(sys/capability.h, [ have_libcap=true ], [ have_libcap=false ])
|
||||||
|
AC_SUBST(have_libcap)
|
||||||
|
])
|
||||||
@@ -71,6 +71,11 @@ ifeq ($(HAVE_URING), true)
|
|||||||
LLDLIBS += -luring
|
LLDLIBS += -luring
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
SUBDIRS += idmapped-mounts
|
||||||
|
ifeq ($(HAVE_LIBCAP), true)
|
||||||
|
LLDLIBS += -lcap
|
||||||
|
endif
|
||||||
|
|
||||||
CFILES = $(TARGETS:=.c)
|
CFILES = $(TARGETS:=.c)
|
||||||
LDIRT = $(TARGETS) fssum
|
LDIRT = $(TARGETS) fssum
|
||||||
|
|
||||||
|
|||||||
@@ -26,70 +26,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* open_tree() */
|
#include "idmapped-mounts/missing.h"
|
||||||
#ifndef OPEN_TREE_CLONE
|
|
||||||
#define OPEN_TREE_CLONE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef OPEN_TREE_CLOEXEC
|
|
||||||
#define OPEN_TREE_CLOEXEC O_CLOEXEC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __NR_open_tree
|
|
||||||
#if defined __alpha__
|
|
||||||
#define __NR_open_tree 538
|
|
||||||
#elif defined _MIPS_SIM
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
|
|
||||||
#define __NR_open_tree 4428
|
|
||||||
#endif
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
|
|
||||||
#define __NR_open_tree 6428
|
|
||||||
#endif
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
|
|
||||||
#define __NR_open_tree 5428
|
|
||||||
#endif
|
|
||||||
#elif defined __ia64__
|
|
||||||
#define __NR_open_tree (428 + 1024)
|
|
||||||
#else
|
|
||||||
#define __NR_open_tree 428
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* move_mount() */
|
|
||||||
#ifndef MOVE_MOUNT_F_EMPTY_PATH
|
|
||||||
#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __NR_move_mount
|
|
||||||
#if defined __alpha__
|
|
||||||
#define __NR_move_mount 539
|
|
||||||
#elif defined _MIPS_SIM
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
|
|
||||||
#define __NR_move_mount 4429
|
|
||||||
#endif
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
|
|
||||||
#define __NR_move_mount 6429
|
|
||||||
#endif
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
|
|
||||||
#define __NR_move_mount 5429
|
|
||||||
#endif
|
|
||||||
#elif defined __ia64__
|
|
||||||
#define __NR_move_mount (428 + 1024)
|
|
||||||
#else
|
|
||||||
#define __NR_move_mount 429
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags)
|
|
||||||
{
|
|
||||||
return syscall(__NR_open_tree, dfd, filename, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int sys_move_mount(int from_dfd, const char *from_pathname, int to_dfd,
|
|
||||||
const char *to_pathname, unsigned int flags)
|
|
||||||
{
|
|
||||||
return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, to_pathname, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_shared_mountpoint(const char *path)
|
static bool is_shared_mountpoint(const char *path)
|
||||||
{
|
{
|
||||||
|
|||||||
+36
-4
@@ -19,6 +19,7 @@
|
|||||||
*
|
*
|
||||||
* Test for machine features
|
* Test for machine features
|
||||||
* -A test whether AIO syscalls are available
|
* -A test whether AIO syscalls are available
|
||||||
|
* -r test whether mount_setattr syscall is supported
|
||||||
* -R test whether IO_URING syscalls are available
|
* -R test whether IO_URING syscalls are available
|
||||||
* -o report a number of online cpus
|
* -o report a number of online cpus
|
||||||
* -s report pagesize
|
* -s report pagesize
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
#include <sys/quota.h>
|
#include <sys/quota.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef HAVE_XFS_XQM_H
|
#ifdef HAVE_XFS_XQM_H
|
||||||
@@ -44,6 +46,8 @@
|
|||||||
#include <liburing.h>
|
#include <liburing.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "idmapped-mounts/missing.h"
|
||||||
|
|
||||||
#ifndef USRQUOTA
|
#ifndef USRQUOTA
|
||||||
#define USRQUOTA 0
|
#define USRQUOTA 0
|
||||||
#endif
|
#endif
|
||||||
@@ -64,7 +68,7 @@ usage(void)
|
|||||||
fprintf(stderr, "Usage: feature [-v] -<q|u|g|p|U|G|P> <filesystem>\n");
|
fprintf(stderr, "Usage: feature [-v] -<q|u|g|p|U|G|P> <filesystem>\n");
|
||||||
fprintf(stderr, " feature [-v] -c <file>\n");
|
fprintf(stderr, " feature [-v] -c <file>\n");
|
||||||
fprintf(stderr, " feature [-v] -t <file>\n");
|
fprintf(stderr, " feature [-v] -t <file>\n");
|
||||||
fprintf(stderr, " feature -A | -R | -o | -s | -w\n");
|
fprintf(stderr, " feature -A | -r | -R | -o | -s | -w\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +247,27 @@ check_uring_support(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_mount_setattr_support(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct mount_attr attr = {
|
||||||
|
.attr_set = MOUNT_ATTR_IDMAP,
|
||||||
|
.userns_fd = -EBADF,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* mount_setattr() syscall not supported. */
|
||||||
|
err = sys_mount_setattr(-EBADF, "", AT_EMPTY_PATH, NULL, 0);
|
||||||
|
if (err && errno == ENOSYS)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* idmapped mounts not supported */
|
||||||
|
err = sys_mount_setattr(-EBADF, ".", AT_EMPTY_PATH, &attr, sizeof(attr));
|
||||||
|
if (err && errno == E2BIG)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
@@ -256,6 +281,7 @@ main(int argc, char **argv)
|
|||||||
int pflag = 0;
|
int pflag = 0;
|
||||||
int Pflag = 0;
|
int Pflag = 0;
|
||||||
int qflag = 0;
|
int qflag = 0;
|
||||||
|
int rflag = 0;
|
||||||
int Rflag = 0;
|
int Rflag = 0;
|
||||||
int sflag = 0;
|
int sflag = 0;
|
||||||
int uflag = 0;
|
int uflag = 0;
|
||||||
@@ -264,7 +290,7 @@ main(int argc, char **argv)
|
|||||||
int oflag = 0;
|
int oflag = 0;
|
||||||
char *fs = NULL;
|
char *fs = NULL;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "ActgGopPqRsuUvw")) != EOF) {
|
while ((c = getopt(argc, argv, "ActgGopPqrRsuUvw")) != EOF) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'A':
|
case 'A':
|
||||||
Aflag++;
|
Aflag++;
|
||||||
@@ -293,6 +319,9 @@ main(int argc, char **argv)
|
|||||||
case 'q':
|
case 'q':
|
||||||
qflag++;
|
qflag++;
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
rflag++;
|
||||||
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
Rflag++;
|
Rflag++;
|
||||||
break;
|
break;
|
||||||
@@ -321,10 +350,10 @@ main(int argc, char **argv)
|
|||||||
if (optind != argc-1) /* need a device */
|
if (optind != argc-1) /* need a device */
|
||||||
usage();
|
usage();
|
||||||
fs = argv[argc-1];
|
fs = argv[argc-1];
|
||||||
} else if (Aflag || Rflag || wflag || sflag || oflag) {
|
} else if (Aflag || rflag || Rflag || wflag || sflag || oflag) {
|
||||||
if (optind != argc)
|
if (optind != argc)
|
||||||
usage();
|
usage();
|
||||||
} else
|
} else
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
if (cflag)
|
if (cflag)
|
||||||
@@ -349,6 +378,9 @@ main(int argc, char **argv)
|
|||||||
if (Aflag)
|
if (Aflag)
|
||||||
return(check_aio_support());
|
return(check_aio_support());
|
||||||
|
|
||||||
|
if (rflag)
|
||||||
|
return(check_mount_setattr_support());
|
||||||
|
|
||||||
if (Rflag)
|
if (Rflag)
|
||||||
return(check_uring_support());
|
return(check_uring_support());
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
TOPDIR = ../..
|
||||||
|
include $(TOPDIR)/include/builddefs
|
||||||
|
|
||||||
|
TARGETS = idmapped-mounts
|
||||||
|
|
||||||
|
CFILES = idmapped-mounts.c utils.c
|
||||||
|
HFILES = missing.h utils.h
|
||||||
|
LLDLIBS += -pthread
|
||||||
|
LDIRT = $(TARGETS)
|
||||||
|
|
||||||
|
ifeq ($(HAVE_LIBCAP), true)
|
||||||
|
LLDLIBS += -lcap
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_URING), true)
|
||||||
|
LLDLIBS += -luring
|
||||||
|
endif
|
||||||
|
|
||||||
|
default: depend $(TARGETS)
|
||||||
|
|
||||||
|
depend: .dep
|
||||||
|
|
||||||
|
include $(BUILDRULES)
|
||||||
|
|
||||||
|
$(TARGETS): $(CFILES)
|
||||||
|
@echo " [CC] $@"
|
||||||
|
$(Q)$(LTLINK) $(CFILES) -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS)
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(INSTALL) -m 755 -d $(PKG_LIB_DIR)/src/idmapped-mounts
|
||||||
|
$(INSTALL) -m 755 $(TARGETS) $(PKG_LIB_DIR)/src/idmapped-mounts
|
||||||
|
|
||||||
|
-include .dep
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,151 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#ifndef __IDMAP_MISSING_H
|
||||||
|
#define __IDMAP_MISSING_H
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include "../global.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifndef __NR_mount_setattr
|
||||||
|
#if defined __alpha__
|
||||||
|
#define __NR_mount_setattr 552
|
||||||
|
#elif defined _MIPS_SIM
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
|
||||||
|
#define __NR_mount_setattr (442 + 4000)
|
||||||
|
#endif
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
|
||||||
|
#define __NR_mount_setattr (442 + 6000)
|
||||||
|
#endif
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
|
||||||
|
#define __NR_mount_setattr (442 + 5000)
|
||||||
|
#endif
|
||||||
|
#elif defined __ia64__
|
||||||
|
#define __NR_mount_setattr (442 + 1024)
|
||||||
|
#else
|
||||||
|
#define __NR_mount_setattr 442
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __NR_open_tree
|
||||||
|
#if defined __alpha__
|
||||||
|
#define __NR_open_tree 538
|
||||||
|
#elif defined _MIPS_SIM
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
|
||||||
|
#define __NR_open_tree 4428
|
||||||
|
#endif
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
|
||||||
|
#define __NR_open_tree 6428
|
||||||
|
#endif
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
|
||||||
|
#define __NR_open_tree 5428
|
||||||
|
#endif
|
||||||
|
#elif defined __ia64__
|
||||||
|
#define __NR_open_tree (428 + 1024)
|
||||||
|
#else
|
||||||
|
#define __NR_open_tree 428
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __NR_move_mount
|
||||||
|
#if defined __alpha__
|
||||||
|
#define __NR_move_mount 539
|
||||||
|
#elif defined _MIPS_SIM
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
|
||||||
|
#define __NR_move_mount 4429
|
||||||
|
#endif
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
|
||||||
|
#define __NR_move_mount 6429
|
||||||
|
#endif
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
|
||||||
|
#define __NR_move_mount 5429
|
||||||
|
#endif
|
||||||
|
#elif defined __ia64__
|
||||||
|
#define __NR_move_mount (428 + 1024)
|
||||||
|
#else
|
||||||
|
#define __NR_move_mount 429
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MNT_DETACH
|
||||||
|
#define MNT_DETACH 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MS_REC
|
||||||
|
#define MS_REC 1638
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MS_PRIVATE
|
||||||
|
#define MS_PRIVATE (1 << 18)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MOVE_MOUNT_F_EMPTY_PATH
|
||||||
|
#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MOUNT_ATTR_IDMAP
|
||||||
|
#define MOUNT_ATTR_IDMAP 0x00100000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OPEN_TREE_CLONE
|
||||||
|
#define OPEN_TREE_CLONE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OPEN_TREE_CLOEXEC
|
||||||
|
#define OPEN_TREE_CLOEXEC O_CLOEXEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef AT_RECURSIVE
|
||||||
|
#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRUCT_MOUNT_ATTR
|
||||||
|
struct mount_attr {
|
||||||
|
__u64 attr_set;
|
||||||
|
__u64 attr_clr;
|
||||||
|
__u64 propagation;
|
||||||
|
__u64 userns_fd;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags,
|
||||||
|
struct mount_attr *attr, size_t size)
|
||||||
|
{
|
||||||
|
return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_open_tree, dfd, filename, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sys_move_mount(int from_dfd, const char *from_pathname, int to_dfd,
|
||||||
|
const char *to_pathname, unsigned int flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, to_pathname, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sys_mount(const char *source, const char *target, const char *fstype,
|
||||||
|
unsigned long int flags, const void *data)
|
||||||
|
{
|
||||||
|
return syscall(__NR_mount, source, target, fstype, flags, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sys_umount2(const char *path, int flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_umount2, path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __IDMAP_MISSING_H */
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
ssize_t read_nointr(int fd, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = read(fd, buf, count);
|
||||||
|
} while (ret < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t write_nointr(int fd, const void *buf, size_t count)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = write(fd, buf, count);
|
||||||
|
} while (ret < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_file(const char *path, const void *buf, size_t count)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = write_nointr(fd, buf, count);
|
||||||
|
close(fd);
|
||||||
|
if (ret < 0 || (size_t)ret != count)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int map_ids(pid_t pid, unsigned long nsid, unsigned long hostid,
|
||||||
|
unsigned long range)
|
||||||
|
{
|
||||||
|
char map[100], procfile[256];
|
||||||
|
|
||||||
|
snprintf(procfile, sizeof(procfile), "/proc/%d/uid_map", pid);
|
||||||
|
snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
|
||||||
|
if (write_file(procfile, map, strlen(map)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
|
snprintf(procfile, sizeof(procfile), "/proc/%d/gid_map", pid);
|
||||||
|
snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
|
||||||
|
if (write_file(procfile, map, strlen(map)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __STACK_SIZE (8 * 1024 * 1024)
|
||||||
|
pid_t do_clone(int (*fn)(void *), void *arg, int flags)
|
||||||
|
{
|
||||||
|
void *stack;
|
||||||
|
|
||||||
|
stack = malloc(__STACK_SIZE);
|
||||||
|
if (!stack)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
#ifdef __ia64__
|
||||||
|
return __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg, NULL);
|
||||||
|
#else
|
||||||
|
return clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_userns_fd_cb(void *data)
|
||||||
|
{
|
||||||
|
return kill(getpid(), SIGSTOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
pid_t pid;
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER);
|
||||||
|
if (pid < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
ret = map_ids(pid, nsid, hostid, range);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
|
||||||
|
ret = open(path, O_RDONLY | O_CLOEXEC);
|
||||||
|
kill(pid, SIGKILL);
|
||||||
|
wait_for_pid(pid);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wait_for_pid(pid_t pid)
|
||||||
|
{
|
||||||
|
int status, ret;
|
||||||
|
|
||||||
|
again:
|
||||||
|
ret = waitpid(pid, &status, 0);
|
||||||
|
if (ret == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WIFEXITED(status))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#ifndef __IDMAP_UTILS_H
|
||||||
|
#define __IDMAP_UTILS_H
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "missing.h"
|
||||||
|
|
||||||
|
extern pid_t do_clone(int (*fn)(void *), void *arg, int flags);
|
||||||
|
extern int get_userns_fd(unsigned long nsid, unsigned long hostid,
|
||||||
|
unsigned long range);
|
||||||
|
extern ssize_t read_nointr(int fd, void *buf, size_t count);
|
||||||
|
extern int wait_for_pid(pid_t pid);
|
||||||
|
extern ssize_t write_nointr(int fd, const void *buf, size_t count);
|
||||||
|
|
||||||
|
#endif /* __IDMAP_UTILS_H */
|
||||||
Executable
+42
@@ -0,0 +1,42 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
# Copyright (c) 2021 Christian Brauner. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# FS QA Test 633
|
||||||
|
#
|
||||||
|
# Test that idmapped mounts behave correctly.
|
||||||
|
#
|
||||||
|
seq=`basename $0`
|
||||||
|
seqres=$RESULT_DIR/$seq
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
tmp=/tmp/$$
|
||||||
|
status=1 # failure is the default!
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
cd /
|
||||||
|
rm -f $tmp.*
|
||||||
|
}
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common/rc
|
||||||
|
. ./common/filter
|
||||||
|
|
||||||
|
# remove previous $seqres.full before test
|
||||||
|
rm -f $seqres.full
|
||||||
|
|
||||||
|
# real QA test starts here
|
||||||
|
|
||||||
|
_supported_fs generic
|
||||||
|
_require_idmapped_mounts
|
||||||
|
_require_test
|
||||||
|
|
||||||
|
echo "Silence is golden"
|
||||||
|
|
||||||
|
$here/src/idmapped-mounts/idmapped-mounts --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP"
|
||||||
|
|
||||||
|
status=$?
|
||||||
|
exit
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
QA output created by 633
|
||||||
|
Silence is golden
|
||||||
@@ -635,3 +635,4 @@
|
|||||||
630 auto quick rw dedupe clone
|
630 auto quick rw dedupe clone
|
||||||
631 auto rw overlay rename
|
631 auto rw overlay rename
|
||||||
632 auto quick mount
|
632 auto quick mount
|
||||||
|
633 auto quick atime attr cap idmapped io_uring mount perms rw unlink
|
||||||
|
|||||||
Reference in New Issue
Block a user