xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/mount/nosymfollow-test.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE
3*053f45beSAndroid Build Coastguard Worker #include <errno.h>
4*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
5*053f45beSAndroid Build Coastguard Worker #include <limits.h>
6*053f45beSAndroid Build Coastguard Worker #include <sched.h>
7*053f45beSAndroid Build Coastguard Worker #include <stdarg.h>
8*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
9*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
10*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
11*053f45beSAndroid Build Coastguard Worker #include <string.h>
12*053f45beSAndroid Build Coastguard Worker #include <sys/mount.h>
13*053f45beSAndroid Build Coastguard Worker #include <sys/stat.h>
14*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
15*053f45beSAndroid Build Coastguard Worker #include <sys/vfs.h>
16*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
17*053f45beSAndroid Build Coastguard Worker 
18*053f45beSAndroid Build Coastguard Worker #ifndef MS_NOSYMFOLLOW
19*053f45beSAndroid Build Coastguard Worker # define MS_NOSYMFOLLOW 256     /* Do not follow symlinks */
20*053f45beSAndroid Build Coastguard Worker #endif
21*053f45beSAndroid Build Coastguard Worker 
22*053f45beSAndroid Build Coastguard Worker #ifndef ST_NOSYMFOLLOW
23*053f45beSAndroid Build Coastguard Worker # define ST_NOSYMFOLLOW 0x2000  /* Do not follow symlinks */
24*053f45beSAndroid Build Coastguard Worker #endif
25*053f45beSAndroid Build Coastguard Worker 
26*053f45beSAndroid Build Coastguard Worker #define DATA "/tmp/data"
27*053f45beSAndroid Build Coastguard Worker #define LINK "/tmp/symlink"
28*053f45beSAndroid Build Coastguard Worker #define TMP  "/tmp"
29*053f45beSAndroid Build Coastguard Worker 
die(char * fmt,...)30*053f45beSAndroid Build Coastguard Worker static void die(char *fmt, ...)
31*053f45beSAndroid Build Coastguard Worker {
32*053f45beSAndroid Build Coastguard Worker 	va_list ap;
33*053f45beSAndroid Build Coastguard Worker 
34*053f45beSAndroid Build Coastguard Worker 	va_start(ap, fmt);
35*053f45beSAndroid Build Coastguard Worker 	vfprintf(stderr, fmt, ap);
36*053f45beSAndroid Build Coastguard Worker 	va_end(ap);
37*053f45beSAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
38*053f45beSAndroid Build Coastguard Worker }
39*053f45beSAndroid Build Coastguard Worker 
vmaybe_write_file(bool enoent_ok,char * filename,char * fmt,va_list ap)40*053f45beSAndroid Build Coastguard Worker static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt,
41*053f45beSAndroid Build Coastguard Worker 		va_list ap)
42*053f45beSAndroid Build Coastguard Worker {
43*053f45beSAndroid Build Coastguard Worker 	ssize_t written;
44*053f45beSAndroid Build Coastguard Worker 	char buf[4096];
45*053f45beSAndroid Build Coastguard Worker 	int buf_len;
46*053f45beSAndroid Build Coastguard Worker 	int fd;
47*053f45beSAndroid Build Coastguard Worker 
48*053f45beSAndroid Build Coastguard Worker 	buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
49*053f45beSAndroid Build Coastguard Worker 	if (buf_len < 0)
50*053f45beSAndroid Build Coastguard Worker 		die("vsnprintf failed: %s\n", strerror(errno));
51*053f45beSAndroid Build Coastguard Worker 
52*053f45beSAndroid Build Coastguard Worker 	if (buf_len >= sizeof(buf))
53*053f45beSAndroid Build Coastguard Worker 		die("vsnprintf output truncated\n");
54*053f45beSAndroid Build Coastguard Worker 
55*053f45beSAndroid Build Coastguard Worker 	fd = open(filename, O_WRONLY);
56*053f45beSAndroid Build Coastguard Worker 	if (fd < 0) {
57*053f45beSAndroid Build Coastguard Worker 		if ((errno == ENOENT) && enoent_ok)
58*053f45beSAndroid Build Coastguard Worker 			return;
59*053f45beSAndroid Build Coastguard Worker 		die("open of %s failed: %s\n", filename, strerror(errno));
60*053f45beSAndroid Build Coastguard Worker 	}
61*053f45beSAndroid Build Coastguard Worker 
62*053f45beSAndroid Build Coastguard Worker 	written = write(fd, buf, buf_len);
63*053f45beSAndroid Build Coastguard Worker 	if (written != buf_len) {
64*053f45beSAndroid Build Coastguard Worker 		if (written >= 0) {
65*053f45beSAndroid Build Coastguard Worker 			die("short write to %s\n", filename);
66*053f45beSAndroid Build Coastguard Worker 		} else {
67*053f45beSAndroid Build Coastguard Worker 			die("write to %s failed: %s\n",
68*053f45beSAndroid Build Coastguard Worker 				filename, strerror(errno));
69*053f45beSAndroid Build Coastguard Worker 		}
70*053f45beSAndroid Build Coastguard Worker 	}
71*053f45beSAndroid Build Coastguard Worker 
72*053f45beSAndroid Build Coastguard Worker 	if (close(fd) != 0)
73*053f45beSAndroid Build Coastguard Worker 		die("close of %s failed: %s\n", filename, strerror(errno));
74*053f45beSAndroid Build Coastguard Worker }
75*053f45beSAndroid Build Coastguard Worker 
maybe_write_file(char * filename,char * fmt,...)76*053f45beSAndroid Build Coastguard Worker static void maybe_write_file(char *filename, char *fmt, ...)
77*053f45beSAndroid Build Coastguard Worker {
78*053f45beSAndroid Build Coastguard Worker 	va_list ap;
79*053f45beSAndroid Build Coastguard Worker 
80*053f45beSAndroid Build Coastguard Worker 	va_start(ap, fmt);
81*053f45beSAndroid Build Coastguard Worker 	vmaybe_write_file(true, filename, fmt, ap);
82*053f45beSAndroid Build Coastguard Worker 	va_end(ap);
83*053f45beSAndroid Build Coastguard Worker }
84*053f45beSAndroid Build Coastguard Worker 
write_file(char * filename,char * fmt,...)85*053f45beSAndroid Build Coastguard Worker static void write_file(char *filename, char *fmt, ...)
86*053f45beSAndroid Build Coastguard Worker {
87*053f45beSAndroid Build Coastguard Worker 	va_list ap;
88*053f45beSAndroid Build Coastguard Worker 
89*053f45beSAndroid Build Coastguard Worker 	va_start(ap, fmt);
90*053f45beSAndroid Build Coastguard Worker 	vmaybe_write_file(false, filename, fmt, ap);
91*053f45beSAndroid Build Coastguard Worker 	va_end(ap);
92*053f45beSAndroid Build Coastguard Worker }
93*053f45beSAndroid Build Coastguard Worker 
create_and_enter_ns(void)94*053f45beSAndroid Build Coastguard Worker static void create_and_enter_ns(void)
95*053f45beSAndroid Build Coastguard Worker {
96*053f45beSAndroid Build Coastguard Worker 	uid_t uid = getuid();
97*053f45beSAndroid Build Coastguard Worker 	gid_t gid = getgid();
98*053f45beSAndroid Build Coastguard Worker 
99*053f45beSAndroid Build Coastguard Worker 	if (unshare(CLONE_NEWUSER) != 0)
100*053f45beSAndroid Build Coastguard Worker 		die("unshare(CLONE_NEWUSER) failed: %s\n", strerror(errno));
101*053f45beSAndroid Build Coastguard Worker 
102*053f45beSAndroid Build Coastguard Worker 	maybe_write_file("/proc/self/setgroups", "deny");
103*053f45beSAndroid Build Coastguard Worker 	write_file("/proc/self/uid_map", "0 %d 1", uid);
104*053f45beSAndroid Build Coastguard Worker 	write_file("/proc/self/gid_map", "0 %d 1", gid);
105*053f45beSAndroid Build Coastguard Worker 
106*053f45beSAndroid Build Coastguard Worker 	if (setgid(0) != 0)
107*053f45beSAndroid Build Coastguard Worker 		die("setgid(0) failed %s\n", strerror(errno));
108*053f45beSAndroid Build Coastguard Worker 	if (setuid(0) != 0)
109*053f45beSAndroid Build Coastguard Worker 		die("setuid(0) failed %s\n", strerror(errno));
110*053f45beSAndroid Build Coastguard Worker 
111*053f45beSAndroid Build Coastguard Worker 	if (unshare(CLONE_NEWNS) != 0)
112*053f45beSAndroid Build Coastguard Worker 		die("unshare(CLONE_NEWNS) failed: %s\n", strerror(errno));
113*053f45beSAndroid Build Coastguard Worker }
114*053f45beSAndroid Build Coastguard Worker 
setup_symlink(void)115*053f45beSAndroid Build Coastguard Worker static void setup_symlink(void)
116*053f45beSAndroid Build Coastguard Worker {
117*053f45beSAndroid Build Coastguard Worker 	int data, err;
118*053f45beSAndroid Build Coastguard Worker 
119*053f45beSAndroid Build Coastguard Worker 	data = creat(DATA, O_RDWR);
120*053f45beSAndroid Build Coastguard Worker 	if (data < 0)
121*053f45beSAndroid Build Coastguard Worker 		die("creat failed: %s\n", strerror(errno));
122*053f45beSAndroid Build Coastguard Worker 
123*053f45beSAndroid Build Coastguard Worker 	err = symlink(DATA, LINK);
124*053f45beSAndroid Build Coastguard Worker 	if (err < 0)
125*053f45beSAndroid Build Coastguard Worker 		die("symlink failed: %s\n", strerror(errno));
126*053f45beSAndroid Build Coastguard Worker 
127*053f45beSAndroid Build Coastguard Worker 	if (close(data) != 0)
128*053f45beSAndroid Build Coastguard Worker 		die("close of %s failed: %s\n", DATA, strerror(errno));
129*053f45beSAndroid Build Coastguard Worker }
130*053f45beSAndroid Build Coastguard Worker 
test_link_traversal(bool nosymfollow)131*053f45beSAndroid Build Coastguard Worker static void test_link_traversal(bool nosymfollow)
132*053f45beSAndroid Build Coastguard Worker {
133*053f45beSAndroid Build Coastguard Worker 	int link;
134*053f45beSAndroid Build Coastguard Worker 
135*053f45beSAndroid Build Coastguard Worker 	link = open(LINK, 0, O_RDWR);
136*053f45beSAndroid Build Coastguard Worker 	if (nosymfollow) {
137*053f45beSAndroid Build Coastguard Worker 		if ((link != -1 || errno != ELOOP)) {
138*053f45beSAndroid Build Coastguard Worker 			die("link traversal unexpected result: %d, %s\n",
139*053f45beSAndroid Build Coastguard Worker 					link, strerror(errno));
140*053f45beSAndroid Build Coastguard Worker 		}
141*053f45beSAndroid Build Coastguard Worker 	} else {
142*053f45beSAndroid Build Coastguard Worker 		if (link < 0)
143*053f45beSAndroid Build Coastguard Worker 			die("link traversal failed: %s\n", strerror(errno));
144*053f45beSAndroid Build Coastguard Worker 
145*053f45beSAndroid Build Coastguard Worker 		if (close(link) != 0)
146*053f45beSAndroid Build Coastguard Worker 			die("close of link failed: %s\n", strerror(errno));
147*053f45beSAndroid Build Coastguard Worker 	}
148*053f45beSAndroid Build Coastguard Worker }
149*053f45beSAndroid Build Coastguard Worker 
test_readlink(void)150*053f45beSAndroid Build Coastguard Worker static void test_readlink(void)
151*053f45beSAndroid Build Coastguard Worker {
152*053f45beSAndroid Build Coastguard Worker 	char buf[4096];
153*053f45beSAndroid Build Coastguard Worker 	ssize_t ret;
154*053f45beSAndroid Build Coastguard Worker 
155*053f45beSAndroid Build Coastguard Worker 	bzero(buf, sizeof(buf));
156*053f45beSAndroid Build Coastguard Worker 
157*053f45beSAndroid Build Coastguard Worker 	ret = readlink(LINK, buf, sizeof(buf));
158*053f45beSAndroid Build Coastguard Worker 	if (ret < 0)
159*053f45beSAndroid Build Coastguard Worker 		die("readlink failed: %s\n", strerror(errno));
160*053f45beSAndroid Build Coastguard Worker 	if (strcmp(buf, DATA) != 0)
161*053f45beSAndroid Build Coastguard Worker 		die("readlink strcmp failed: '%s' '%s'\n", buf, DATA);
162*053f45beSAndroid Build Coastguard Worker }
163*053f45beSAndroid Build Coastguard Worker 
test_realpath(void)164*053f45beSAndroid Build Coastguard Worker static void test_realpath(void)
165*053f45beSAndroid Build Coastguard Worker {
166*053f45beSAndroid Build Coastguard Worker 	char *path = realpath(LINK, NULL);
167*053f45beSAndroid Build Coastguard Worker 
168*053f45beSAndroid Build Coastguard Worker 	if (!path)
169*053f45beSAndroid Build Coastguard Worker 		die("realpath failed: %s\n", strerror(errno));
170*053f45beSAndroid Build Coastguard Worker 	if (strcmp(path, DATA) != 0)
171*053f45beSAndroid Build Coastguard Worker 		die("realpath strcmp failed\n");
172*053f45beSAndroid Build Coastguard Worker 
173*053f45beSAndroid Build Coastguard Worker 	free(path);
174*053f45beSAndroid Build Coastguard Worker }
175*053f45beSAndroid Build Coastguard Worker 
test_statfs(bool nosymfollow)176*053f45beSAndroid Build Coastguard Worker static void test_statfs(bool nosymfollow)
177*053f45beSAndroid Build Coastguard Worker {
178*053f45beSAndroid Build Coastguard Worker 	struct statfs buf;
179*053f45beSAndroid Build Coastguard Worker 	int ret;
180*053f45beSAndroid Build Coastguard Worker 
181*053f45beSAndroid Build Coastguard Worker 	ret = statfs(TMP, &buf);
182*053f45beSAndroid Build Coastguard Worker 	if (ret)
183*053f45beSAndroid Build Coastguard Worker 		die("statfs failed: %s\n", strerror(errno));
184*053f45beSAndroid Build Coastguard Worker 
185*053f45beSAndroid Build Coastguard Worker 	if (nosymfollow) {
186*053f45beSAndroid Build Coastguard Worker 		if ((buf.f_flags & ST_NOSYMFOLLOW) == 0)
187*053f45beSAndroid Build Coastguard Worker 			die("ST_NOSYMFOLLOW not set on %s\n", TMP);
188*053f45beSAndroid Build Coastguard Worker 	} else {
189*053f45beSAndroid Build Coastguard Worker 		if ((buf.f_flags & ST_NOSYMFOLLOW) != 0)
190*053f45beSAndroid Build Coastguard Worker 			die("ST_NOSYMFOLLOW set on %s\n", TMP);
191*053f45beSAndroid Build Coastguard Worker 	}
192*053f45beSAndroid Build Coastguard Worker }
193*053f45beSAndroid Build Coastguard Worker 
run_tests(bool nosymfollow)194*053f45beSAndroid Build Coastguard Worker static void run_tests(bool nosymfollow)
195*053f45beSAndroid Build Coastguard Worker {
196*053f45beSAndroid Build Coastguard Worker 	test_link_traversal(nosymfollow);
197*053f45beSAndroid Build Coastguard Worker 	test_readlink();
198*053f45beSAndroid Build Coastguard Worker 	test_realpath();
199*053f45beSAndroid Build Coastguard Worker 	test_statfs(nosymfollow);
200*053f45beSAndroid Build Coastguard Worker }
201*053f45beSAndroid Build Coastguard Worker 
main(int argc,char ** argv)202*053f45beSAndroid Build Coastguard Worker int main(int argc, char **argv)
203*053f45beSAndroid Build Coastguard Worker {
204*053f45beSAndroid Build Coastguard Worker 	create_and_enter_ns();
205*053f45beSAndroid Build Coastguard Worker 
206*053f45beSAndroid Build Coastguard Worker 	if (mount("testing", TMP, "ramfs", 0, NULL) != 0)
207*053f45beSAndroid Build Coastguard Worker 		die("mount failed: %s\n", strerror(errno));
208*053f45beSAndroid Build Coastguard Worker 
209*053f45beSAndroid Build Coastguard Worker 	setup_symlink();
210*053f45beSAndroid Build Coastguard Worker 	run_tests(false);
211*053f45beSAndroid Build Coastguard Worker 
212*053f45beSAndroid Build Coastguard Worker 	if (mount("testing", TMP, "ramfs", MS_REMOUNT|MS_NOSYMFOLLOW, NULL) != 0)
213*053f45beSAndroid Build Coastguard Worker 		die("remount failed: %s\n", strerror(errno));
214*053f45beSAndroid Build Coastguard Worker 
215*053f45beSAndroid Build Coastguard Worker 	run_tests(true);
216*053f45beSAndroid Build Coastguard Worker 
217*053f45beSAndroid Build Coastguard Worker 	return EXIT_SUCCESS;
218*053f45beSAndroid Build Coastguard Worker }
219