1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <stdbool.h>
33 
34 int
35 main(int argc, char *argv[])
36 {
37 	const char *name, *phase;
38 	mode_t extra;
39 	struct stat st;
40 
41 	if (argc < 3) {
42 		fprintf(stderr, "Invalid argc\n");
43 		exit(1);
44 	}
45 
46 	name = argv[1];
47 	if (strcmp(name, "SUID") == 0) {
48 		extra = S_ISUID;
49 	} else if (strcmp(name, "SGID") == 0) {
50 		extra = S_ISGID;
51 	} else if (strcmp(name, "SUID_SGID") == 0) {
52 		extra = S_ISUID | S_ISGID;
53 	} else if (strcmp(name, "NONE") == 0) {
54 		extra = 0;
55 	} else {
56 		fprintf(stderr, "Invalid name %s\n", name);
57 		exit(1);
58 	}
59 
60 	const char *testdir = getenv("TESTDIR");
61 	if (!testdir) {
62 		fprintf(stderr, "getenv(TESTDIR)\n");
63 		exit(1);
64 	}
65 
66 	umask(0);
67 	if (stat(testdir, &st) == -1 && mkdir(testdir, 0777) == -1) {
68 		perror("mkdir");
69 		exit(2);
70 	}
71 
72 	char fpath[1024];
73 	snprintf(fpath, sizeof (fpath), "%s/%s", testdir, name);
74 
75 
76 	phase = argv[2];
77 	if (strcmp(phase, "PRECRASH") == 0) {
78 
79 		/* clean up last run */
80 		unlink(fpath);
81 		if (stat(fpath, &st) == 0) {
82 			fprintf(stderr, "%s exists\n", fpath);
83 			exit(3);
84 		}
85 
86 		int fd;
87 
88 		fd = creat(fpath, 0777 | extra);
89 		if (fd == -1) {
90 			perror("creat");
91 			exit(4);
92 		}
93 		close(fd);
94 
95 		if (setuid(65534) == -1) {
96 			perror("setuid");
97 			exit(5);
98 		}
99 
100 		fd = open(fpath, O_RDWR);
101 		if (fd == -1) {
102 			perror("open");
103 			exit(6);
104 		}
105 
106 		const char buf[] = "test";
107 		if (write(fd, buf, sizeof (buf)) == -1) {
108 			perror("write");
109 			exit(7);
110 		}
111 		close(fd);
112 
113 	} else if (strcmp(phase, "REPLAY") == 0) {
114 		/* created in PRECRASH run */
115 	} else {
116 		fprintf(stderr, "Invalid phase %s\n", phase);
117 		exit(1);
118 	}
119 
120 	if (stat(fpath, &st) == -1) {
121 			perror("stat");
122 			exit(8);
123 		}
124 
125 	/* Verify SUID/SGID are dropped */
126 	mode_t res = st.st_mode & (0777 | S_ISUID | S_ISGID);
127 	if (res != 0777) {
128 		fprintf(stderr, "stat(2) %o\n", res);
129 		exit(9);
130 	}
131 
132 	return (0);
133 }
134