xref: /openbsd/regress/sys/mfs_noperm/nopermtest.c (revision 664789de)
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