~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mount/nosymfollow-test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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>
 17 
 18 #ifndef MS_NOSYMFOLLOW
 19 # define MS_NOSYMFOLLOW 256     /* Do not follow symlinks */
 20 #endif
 21 
 22 #ifndef ST_NOSYMFOLLOW
 23 # define ST_NOSYMFOLLOW 0x2000  /* Do not follow symlinks */
 24 #endif
 25 
 26 #define DATA "/tmp/data"
 27 #define LINK "/tmp/symlink"
 28 #define TMP  "/tmp"
 29 
 30 static void die(char *fmt, ...)
 31 {
 32         va_list ap;
 33 
 34         va_start(ap, fmt);
 35         vfprintf(stderr, fmt, ap);
 36         va_end(ap);
 37         exit(EXIT_FAILURE);
 38 }
 39 
 40 static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt,
 41                 va_list ap)
 42 {
 43         ssize_t written;
 44         char buf[4096];
 45         int buf_len;
 46         int fd;
 47 
 48         buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
 49         if (buf_len < 0)
 50                 die("vsnprintf failed: %s\n", strerror(errno));
 51 
 52         if (buf_len >= sizeof(buf))
 53                 die("vsnprintf output truncated\n");
 54 
 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));
 60         }
 61 
 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));
 69                 }
 70         }
 71 
 72         if (close(fd) != 0)
 73                 die("close of %s failed: %s\n", filename, strerror(errno));
 74 }
 75 
 76 static void maybe_write_file(char *filename, char *fmt, ...)
 77 {
 78         va_list ap;
 79 
 80         va_start(ap, fmt);
 81         vmaybe_write_file(true, filename, fmt, ap);
 82         va_end(ap);
 83 }
 84 
 85 static void write_file(char *filename, char *fmt, ...)
 86 {
 87         va_list ap;
 88 
 89         va_start(ap, fmt);
 90         vmaybe_write_file(false, filename, fmt, ap);
 91         va_end(ap);
 92 }
 93 
 94 static void create_and_enter_ns(void)
 95 {
 96         uid_t uid = getuid();
 97         gid_t gid = getgid();
 98 
 99         if (unshare(CLONE_NEWUSER) != 0)
100                 die("unshare(CLONE_NEWUSER) failed: %s\n", strerror(errno));
101 
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);
105 
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));
110 
111         if (unshare(CLONE_NEWNS) != 0)
112                 die("unshare(CLONE_NEWNS) failed: %s\n", strerror(errno));
113 }
114 
115 static void setup_symlink(void)
116 {
117         int data, err;
118 
119         data = creat(DATA, O_RDWR);
120         if (data < 0)
121                 die("creat failed: %s\n", strerror(errno));
122 
123         err = symlink(DATA, LINK);
124         if (err < 0)
125                 die("symlink failed: %s\n", strerror(errno));
126 
127         if (close(data) != 0)
128                 die("close of %s failed: %s\n", DATA, strerror(errno));
129 }
130 
131 static void test_link_traversal(bool nosymfollow)
132 {
133         int link;
134 
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));
140                 }
141         } else {
142                 if (link < 0)
143                         die("link traversal failed: %s\n", strerror(errno));
144 
145                 if (close(link) != 0)
146                         die("close of link failed: %s\n", strerror(errno));
147         }
148 }
149 
150 static void test_readlink(void)
151 {
152         char buf[4096];
153         ssize_t ret;
154 
155         bzero(buf, sizeof(buf));
156 
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);
162 }
163 
164 static void test_realpath(void)
165 {
166         char *path = realpath(LINK, NULL);
167 
168         if (!path)
169                 die("realpath failed: %s\n", strerror(errno));
170         if (strcmp(path, DATA) != 0)
171                 die("realpath strcmp failed\n");
172 
173         free(path);
174 }
175 
176 static void test_statfs(bool nosymfollow)
177 {
178         struct statfs buf;
179         int ret;
180 
181         ret = statfs(TMP, &buf);
182         if (ret)
183                 die("statfs failed: %s\n", strerror(errno));
184 
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);
191         }
192 }
193 
194 static void run_tests(bool nosymfollow)
195 {
196         test_link_traversal(nosymfollow);
197         test_readlink();
198         test_realpath();
199         test_statfs(nosymfollow);
200 }
201 
202 int main(int argc, char **argv)
203 {
204         create_and_enter_ns();
205 
206         if (mount("testing", TMP, "ramfs", 0, NULL) != 0)
207                 die("mount failed: %s\n", strerror(errno));
208 
209         setup_symlink();
210         run_tests(false);
211 
212         if (mount("testing", TMP, "ramfs", MS_REMOUNT|MS_NOSYMFOLLOW, NULL) != 0)
213                 die("remount failed: %s\n", strerror(errno));
214 
215         run_tests(true);
216 
217         return EXIT_SUCCESS;
218 }
219 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php