Merge tag 'block-5.11-2021-01-10' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / tools / testing / selftests / mount / nosymfollow-test.c
blob650d6d80a1d27a93c982870cc67b1da68db8cac6
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <sched.h>
7 #include <stdarg.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mount.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <sys/vfs.h>
16 #include <unistd.h>
18 #ifndef MS_NOSYMFOLLOW
19 # define MS_NOSYMFOLLOW 256 /* Do not follow symlinks */
20 #endif
22 #ifndef ST_NOSYMFOLLOW
23 # define ST_NOSYMFOLLOW 0x2000 /* Do not follow symlinks */
24 #endif
26 #define DATA "/tmp/data"
27 #define LINK "/tmp/symlink"
28 #define TMP "/tmp"
30 static void die(char *fmt, ...)
32 va_list ap;
34 va_start(ap, fmt);
35 vfprintf(stderr, fmt, ap);
36 va_end(ap);
37 exit(EXIT_FAILURE);
40 static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt,
41 va_list ap)
43 ssize_t written;
44 char buf[4096];
45 int buf_len;
46 int fd;
48 buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
49 if (buf_len < 0)
50 die("vsnprintf failed: %s\n", strerror(errno));
52 if (buf_len >= sizeof(buf))
53 die("vsnprintf output truncated\n");
55 fd = open(filename, O_WRONLY);
56 if (fd < 0) {
57 if ((errno == ENOENT) && enoent_ok)
58 return;
59 die("open of %s failed: %s\n", filename, strerror(errno));
62 written = write(fd, buf, buf_len);
63 if (written != buf_len) {
64 if (written >= 0) {
65 die("short write to %s\n", filename);
66 } else {
67 die("write to %s failed: %s\n",
68 filename, strerror(errno));
72 if (close(fd) != 0)
73 die("close of %s failed: %s\n", filename, strerror(errno));
76 static void maybe_write_file(char *filename, char *fmt, ...)
78 va_list ap;
80 va_start(ap, fmt);
81 vmaybe_write_file(true, filename, fmt, ap);
82 va_end(ap);
85 static void write_file(char *filename, char *fmt, ...)
87 va_list ap;
89 va_start(ap, fmt);
90 vmaybe_write_file(false, filename, fmt, ap);
91 va_end(ap);
94 static void create_and_enter_ns(void)
96 uid_t uid = getuid();
97 gid_t gid = getgid();
99 if (unshare(CLONE_NEWUSER) != 0)
100 die("unshare(CLONE_NEWUSER) failed: %s\n", strerror(errno));
102 maybe_write_file("/proc/self/setgroups", "deny");
103 write_file("/proc/self/uid_map", "0 %d 1", uid);
104 write_file("/proc/self/gid_map", "0 %d 1", gid);
106 if (setgid(0) != 0)
107 die("setgid(0) failed %s\n", strerror(errno));
108 if (setuid(0) != 0)
109 die("setuid(0) failed %s\n", strerror(errno));
111 if (unshare(CLONE_NEWNS) != 0)
112 die("unshare(CLONE_NEWNS) failed: %s\n", strerror(errno));
115 static void setup_symlink(void)
117 int data, err;
119 data = creat(DATA, O_RDWR);
120 if (data < 0)
121 die("creat failed: %s\n", strerror(errno));
123 err = symlink(DATA, LINK);
124 if (err < 0)
125 die("symlink failed: %s\n", strerror(errno));
127 if (close(data) != 0)
128 die("close of %s failed: %s\n", DATA, strerror(errno));
131 static void test_link_traversal(bool nosymfollow)
133 int link;
135 link = open(LINK, 0, O_RDWR);
136 if (nosymfollow) {
137 if ((link != -1 || errno != ELOOP)) {
138 die("link traversal unexpected result: %d, %s\n",
139 link, strerror(errno));
141 } else {
142 if (link < 0)
143 die("link traversal failed: %s\n", strerror(errno));
145 if (close(link) != 0)
146 die("close of link failed: %s\n", strerror(errno));
150 static void test_readlink(void)
152 char buf[4096];
153 ssize_t ret;
155 bzero(buf, sizeof(buf));
157 ret = readlink(LINK, buf, sizeof(buf));
158 if (ret < 0)
159 die("readlink failed: %s\n", strerror(errno));
160 if (strcmp(buf, DATA) != 0)
161 die("readlink strcmp failed: '%s' '%s'\n", buf, DATA);
164 static void test_realpath(void)
166 char *path = realpath(LINK, NULL);
168 if (!path)
169 die("realpath failed: %s\n", strerror(errno));
170 if (strcmp(path, DATA) != 0)
171 die("realpath strcmp failed\n");
173 free(path);
176 static void test_statfs(bool nosymfollow)
178 struct statfs buf;
179 int ret;
181 ret = statfs(TMP, &buf);
182 if (ret)
183 die("statfs failed: %s\n", strerror(errno));
185 if (nosymfollow) {
186 if ((buf.f_flags & ST_NOSYMFOLLOW) == 0)
187 die("ST_NOSYMFOLLOW not set on %s\n", TMP);
188 } else {
189 if ((buf.f_flags & ST_NOSYMFOLLOW) != 0)
190 die("ST_NOSYMFOLLOW set on %s\n", TMP);
194 static void run_tests(bool nosymfollow)
196 test_link_traversal(nosymfollow);
197 test_readlink();
198 test_realpath();
199 test_statfs(nosymfollow);
202 int main(int argc, char **argv)
204 create_and_enter_ns();
206 if (mount("testing", TMP, "ramfs", 0, NULL) != 0)
207 die("mount failed: %s\n", strerror(errno));
209 setup_symlink();
210 run_tests(false);
212 if (mount("testing", TMP, "ramfs", MS_REMOUNT|MS_NOSYMFOLLOW, NULL) != 0)
213 die("remount failed: %s\n", strerror(errno));
215 run_tests(true);
217 return EXIT_SUCCESS;