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