1 /* $OpenBSD: nopermtest.c,v 1.1 2018/12/23 11:23:21 natano Exp $ */
2
3 /*
4 * Copyright (c) 2018 Martin Natano <natano@natano.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/stat.h>
20 #include <sys/time.h>
21
22 #include <err.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30
31 #define EXPECT_OK(expr) do { \
32 int r = (expr); \
33 if (r == -1) { \
34 fprintf(stderr, "FAIL:%d: %s -> r=%d errno=%d(%s)\n", \
35 __LINE__, #expr, r, errno, strerror(errno)); \
36 nfail++; \
37 } \
38 } while (0)
39
40 #define EXPECT_ERRNO(expr, expected_errno) do { \
41 int r = (expr); \
42 if (r != -1 || errno != expected_errno) { \
43 fprintf(stderr, "FAIL:%d: %s -> r=%d errno=%d(%s)\n", \
44 __LINE__, #expr, r, errno, strerror(errno)); \
45 nfail++; \
46 } \
47 } while (0)
48
49 static void check_locked(const char *);
50 static void check_unlocked(const char *);
51 static void check_unlocked_vroot(void);
52 static void check_unlocked_subdir(void);
53
54 __dead static void usage(void);
55
56 static int nfail;
57
58 int
main(int argc,char ** argv)59 main(int argc, char **argv)
60 {
61 const char *mnt, *stage;
62 const char *errstr;
63
64 if (argc != 3)
65 usage();
66
67 mnt = argv[1];
68 stage = argv[2];
69
70 if (strcmp(stage, "locked") == 0)
71 check_locked(mnt);
72 else if (strcmp(stage, "unlocked") == 0)
73 check_unlocked(mnt);
74 else
75 usage();
76
77 return (nfail > 0);
78 }
79
80 static void
check_locked(const char * mnt)81 check_locked(const char *mnt)
82 {
83 char path[PATH_MAX];
84
85 EXPECT_OK(access(mnt, F_OK));
86 EXPECT_ERRNO(access(mnt, R_OK), EACCES);
87 EXPECT_ERRNO(access(mnt, W_OK), EACCES);
88 EXPECT_ERRNO(access(mnt, X_OK), EACCES);
89
90 (void)snprintf(path, PATH_MAX, "%s/stdin", mnt);
91 EXPECT_ERRNO(mknod(path, S_IFCHR | 0700, makedev(22, 0)), EACCES);
92
93 EXPECT_ERRNO(chown(mnt, getuid(), -1), EPERM);
94 EXPECT_ERRNO(chmod(mnt, 0700), EPERM);
95 EXPECT_ERRNO(chflags(mnt, SF_ARCHIVED), EPERM);
96 EXPECT_ERRNO(utimes(mnt, NULL), EACCES);
97 }
98
99 static void
check_unlocked(const char * mnt)100 check_unlocked(const char *mnt)
101 {
102 if (chdir(mnt) == -1)
103 err(1, "chdir");
104
105 check_unlocked_vroot();
106 check_unlocked_subdir();
107 }
108
109 static void
check_unlocked_vroot(void)110 check_unlocked_vroot(void)
111 {
112 int fd;
113
114 EXPECT_OK(access(".", R_OK | W_OK | X_OK));
115
116 EXPECT_ERRNO(mknod("stdin", S_IFCHR | 0700, makedev(22, 0)), EPERM);
117
118 EXPECT_ERRNO(chown(".", 0, -1), EPERM);
119 EXPECT_OK(chmod(".", 0700));
120 EXPECT_ERRNO(chflags(".", SF_ARCHIVED), EPERM);
121 EXPECT_OK(utimes(".", NULL));
122 }
123
124 static void
check_unlocked_subdir(void)125 check_unlocked_subdir(void)
126 {
127 if (mkdir("sub", 0000) == -1)
128 err(1, "mkdir");
129
130 EXPECT_OK(access("sub", R_OK | W_OK | X_OK));
131
132 EXPECT_OK(mknod("sub/stdin", S_IFCHR | 0700, makedev(22, 0)));
133
134 EXPECT_OK(chown("sub", 0, -1));
135 EXPECT_OK(chmod("sub", 0000));
136 EXPECT_OK(chflags("sub", SF_ARCHIVED));
137 EXPECT_OK(utimes("sub", NULL));
138
139 EXPECT_OK(chmod("sub", S_ISVTX | 0700));
140 EXPECT_OK(chown("sub/stdin", 0, -1));
141 EXPECT_OK(rename("sub/stdin", "sub/stdin2"));
142 EXPECT_OK(unlink("sub/stdin2"));
143 }
144
145 __dead static void
usage(void)146 usage(void)
147 {
148 (void)fprintf(stderr, "usage: %s mnt stage\n", getprogname());
149 exit(1);
150 }
151