1 /*
2 * Copyright (c) Kerlabs 2008.
3 * Copyright (c) International Business Machines Corp., 2008
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Created by Renaud Lottiaux
20 */
21
22 /*
23 * Check if setreuid behaves correctly with file permissions.
24 * The test creates a file as ROOT with permissions 0644, does a setreuid
25 * and then tries to open the file with RDWR permissions.
26 * The same test is done in a fork to check if new UIDs are correctly
27 * passed to the son.
28 */
29
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <pwd.h>
37
38 #include "test.h"
39 #include "safe_macros.h"
40 #include "compat_16.h"
41
42 TCID_DEFINE(setreuid07);
43 int TST_TOTAL = 1;
44
45 static char testfile[256] = "";
46 static struct passwd *ltpuser;
47
48 static int fd = -1;
49
50 static void setup(void);
51 static void cleanup(void);
52 static void do_master_child(void);
53
main(int ac,char ** av)54 int main(int ac, char **av)
55 {
56 pid_t pid;
57
58 tst_parse_opts(ac, av, NULL, NULL);
59
60 setup();
61
62 pid = FORK_OR_VFORK();
63 if (pid < 0)
64 tst_brkm(TBROK, cleanup, "Fork failed");
65
66 if (pid == 0)
67 do_master_child();
68
69 tst_record_childstatus(cleanup, pid);
70
71 cleanup();
72 tst_exit();
73 }
74
do_master_child(void)75 static void do_master_child(void)
76 {
77 int lc;
78 int pid;
79 int status;
80
81 for (lc = 0; TEST_LOOPING(lc); lc++) {
82 int tst_fd;
83
84 tst_count = 0;
85
86 if (SETREUID(NULL, 0, ltpuser->pw_uid) == -1) {
87 perror("setreuid failed");
88 exit(TFAIL);
89 }
90
91 /* Test 1: Check the process with new uid cannot open the file
92 * with RDWR permissions.
93 */
94 TEST(tst_fd = open(testfile, O_RDWR));
95
96 if (TEST_RETURN != -1) {
97 printf("open succeeded unexpectedly\n");
98 close(tst_fd);
99 exit(TFAIL);
100 }
101
102 if (TEST_ERRNO == EACCES) {
103 printf("open failed with EACCES as expected\n");
104 } else {
105 perror("open failed unexpectedly");
106 exit(TFAIL);
107 }
108
109 /* Test 2: Check a son process cannot open the file
110 * with RDWR permissions.
111 */
112 pid = FORK_OR_VFORK();
113 if (pid < 0)
114 tst_brkm(TBROK, cleanup, "Fork failed");
115
116 if (pid == 0) {
117 int tst_fd2;
118
119 /* Test to open the file in son process */
120 TEST(tst_fd2 = open(testfile, O_RDWR));
121
122 if (TEST_RETURN != -1) {
123 printf("call succeeded unexpectedly\n");
124 close(tst_fd2);
125 exit(TFAIL);
126 }
127
128 if (TEST_ERRNO == EACCES) {
129 printf("open failed with EACCES as expected\n");
130 exit(TPASS);
131 } else {
132 printf("open failed unexpectedly\n");
133 exit(TFAIL);
134 }
135 } else {
136 /* Wait for son completion */
137 if (waitpid(pid, &status, 0) == -1) {
138 perror("waitpid failed");
139 exit(TFAIL);
140 }
141 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
142 exit(WEXITSTATUS(status));
143 }
144
145 /* Test 3: Fallback to initial uid and check we can again open
146 * the file with RDWR permissions.
147 */
148 tst_count++;
149 if (SETREUID(NULL, 0, 0) == -1) {
150 perror("setreuid failed");
151 exit(TFAIL);
152 }
153
154 TEST(tst_fd = open(testfile, O_RDWR));
155
156 if (TEST_RETURN == -1) {
157 perror("open failed unexpectedly");
158 exit(TFAIL);
159 } else {
160 printf("open call succeeded\n");
161 close(tst_fd);
162 }
163 }
164 exit(TPASS);
165 }
166
setup(void)167 static void setup(void)
168 {
169 tst_require_root();
170
171 ltpuser = getpwnam("nobody");
172 if (ltpuser == NULL)
173 tst_brkm(TBROK, NULL, "nobody must be a valid user.");
174
175 tst_tmpdir();
176
177 sprintf(testfile, "setreuid07file%d.tst", getpid());
178
179 /* Create test file */
180 fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644);
181
182 tst_sig(FORK, DEF_HANDLER, cleanup);
183
184 TEST_PAUSE;
185 }
186
cleanup(void)187 static void cleanup(void)
188 {
189 close(fd);
190
191 tst_rmdir();
192 }
193