brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 2862aae Raw
186 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#define __SANE_USERSPACE_TYPES__ // Use ll644 5#include <inttypes.h>6#include <unistd.h>7#include <stdio.h>8 9#include <linux/unistd.h>10#include <linux/types.h>11#include <linux/mount.h>12#include <sys/syscall.h>13#include <sys/stat.h>14#include <sys/mman.h>15#include <sched.h>16#include <fcntl.h>17 18#include "../../kselftest.h"19#include "log.h"20 21static int sys_fsopen(const char *fsname, unsigned int flags)22{23	return syscall(__NR_fsopen, fsname, flags);24}25 26static int sys_fsconfig(int fd, unsigned int cmd, const char *key, const char *value, int aux)27{28	return syscall(__NR_fsconfig, fd, cmd, key, value, aux);29}30 31static int sys_fsmount(int fd, unsigned int flags, unsigned int attr_flags)32{33	return syscall(__NR_fsmount, fd, flags, attr_flags);34}35static int sys_mount(const char *src, const char *tgt, const char *fst,36		unsigned long flags, const void *data)37{38	return syscall(__NR_mount, src, tgt, fst, flags, data);39}40static int sys_move_mount(int from_dfd, const char *from_pathname,41			  int to_dfd, const char *to_pathname,42			  unsigned int flags)43{44	return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, to_pathname, flags);45}46 47static long get_file_dev_and_inode(void *addr, struct statx *stx)48{49	char buf[4096];50	FILE *mapf;51 52	mapf = fopen("/proc/self/maps", "r");53	if (mapf == NULL)54		return pr_perror("fopen(/proc/self/maps)");55 56	while (fgets(buf, sizeof(buf), mapf)) {57		unsigned long start, end;58		uint32_t maj, min;59		__u64 ino;60 61		if (sscanf(buf, "%lx-%lx %*s %*s %x:%x %llu",62				&start, &end, &maj, &min, &ino) != 5)63			return pr_perror("unable to parse: %s", buf);64		if (start == (unsigned long)addr) {65			stx->stx_dev_major = maj;66			stx->stx_dev_minor = min;67			stx->stx_ino = ino;68			return 0;69		}70	}71 72	return pr_err("unable to find the mapping");73}74 75static int ovl_mount(void)76{77	int tmpfs, fsfd, ovl;78 79	fsfd = sys_fsopen("tmpfs", 0);80	if (fsfd == -1)81		return pr_perror("fsopen(tmpfs)");82 83	if (sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) == -1)84		return pr_perror("FSCONFIG_CMD_CREATE");85 86	tmpfs = sys_fsmount(fsfd, 0, 0);87	if (tmpfs == -1)88		return pr_perror("fsmount");89 90	close(fsfd);91 92	/* overlayfs can't be constructed on top of a detached mount. */93	if (sys_move_mount(tmpfs, "", AT_FDCWD, "/tmp", MOVE_MOUNT_F_EMPTY_PATH))94		return pr_perror("move_mount");95	close(tmpfs);96 97	if (mkdir("/tmp/w", 0755) == -1 ||98	    mkdir("/tmp/u", 0755) == -1 ||99	    mkdir("/tmp/l", 0755) == -1)100		return pr_perror("mkdir");101 102	fsfd = sys_fsopen("overlay", 0);103	if (fsfd == -1)104		return pr_perror("fsopen(overlay)");105	if (sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "test", 0) == -1 ||106	    sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "lowerdir", "/tmp/l", 0) == -1 ||107	    sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "upperdir", "/tmp/u", 0) == -1 ||108	    sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "workdir", "/tmp/w", 0) == -1)109		return pr_perror("fsconfig");110	if (sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) == -1)111		return pr_perror("fsconfig");112	ovl = sys_fsmount(fsfd, 0, 0);113	if (ovl == -1)114		return pr_perror("fsmount");115 116	return ovl;117}118 119/*120 * Check that the file device and inode shown in /proc/pid/maps match values121 * returned by stat(2).122 */123static int test(void)124{125	struct statx stx, mstx;126	int ovl, fd;127	void *addr;128 129	ovl = ovl_mount();130	if (ovl == -1)131		return -1;132 133	fd = openat(ovl, "test", O_RDWR | O_CREAT, 0644);134	if (fd == -1)135		return pr_perror("openat");136 137	addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);138	if (addr == MAP_FAILED)139		return pr_perror("mmap");140 141	if (get_file_dev_and_inode(addr, &mstx))142		return -1;143	if (statx(fd, "", AT_EMPTY_PATH | AT_STATX_SYNC_AS_STAT, STATX_INO, &stx))144		return pr_perror("statx");145 146	if (stx.stx_dev_major != mstx.stx_dev_major ||147	    stx.stx_dev_minor != mstx.stx_dev_minor ||148	    stx.stx_ino != mstx.stx_ino)149		return pr_fail("unmatched dev:ino %x:%x:%llx (expected %x:%x:%llx)\n",150			mstx.stx_dev_major, mstx.stx_dev_minor, mstx.stx_ino,151			stx.stx_dev_major, stx.stx_dev_minor, stx.stx_ino);152 153	ksft_test_result_pass("devices are matched\n");154	return 0;155}156 157int main(int argc, char **argv)158{159	int fsfd;160 161	fsfd = sys_fsopen("overlay", 0);162	if (fsfd == -1) {163		ksft_test_result_skip("unable to create overlay mount\n");164		return 1;165	}166	close(fsfd);167 168	/* Create a new mount namespace to not care about cleaning test mounts. */169	if (unshare(CLONE_NEWNS) == -1) {170		ksft_test_result_skip("unable to create a new mount namespace\n");171		return 1;172	}173	if (sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) == -1) {174		pr_perror("mount");175		return 1;176	}177 178	ksft_set_plan(1);179 180	if (test())181		return 1;182 183	ksft_exit_pass();184	return 0;185}186