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 /******************************************************************************/
20 /*
21 * NAME
22 * setresuid04.c
23 *
24 * DESCRIPTION
25 * Check if setresuid behaves correctly with file permissions.
26 * The test creates a file as ROOT with permissions 0644, does a setresuid
27 * and then tries to open the file with RDWR permissions.
28 * The same test is done in a fork to check if new UIDs are correctly
29 * passed to the son.
30 *
31 * USAGE: <for command-line>
32 * setresuid04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
33 * where, -c n : Run n copies concurrently.
34 * -e : Turn on errno logging.
35 * -i n : Execute test n times.
36 * -I x : Execute test for x seconds.
37 * -P x : Pause for x seconds between iterations.
38 * -t : Turn on syscall timing.
39 *
40 * HISTORY
41 * 07/2001 Created by Renaud Lottiaux
42 *
43 * RESTRICTIONS
44 * Must be run as root.
45 */
46 #define _GNU_SOURCE 1
47 #include <errno.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <sys/wait.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include "test.h"
54 #include "safe_macros.h"
55 #include <pwd.h>
56 #include "compat_16.h"
57
58 TCID_DEFINE(setresuid04);
59 int TST_TOTAL = 1;
60 char nobody_uid[] = "nobody";
61 char testfile[256] = "";
62 struct passwd *ltpuser;
63
64 int fd = -1;
65
66 void setup(void);
67 void cleanup(void);
68 void do_master_child();
69
main(int ac,char ** av)70 int main(int ac, char **av)
71 {
72 pid_t pid;
73
74 tst_parse_opts(ac, av, NULL, NULL);
75 setup();
76
77 pid = FORK_OR_VFORK();
78 if (pid < 0)
79 tst_brkm(TBROK, cleanup, "Fork failed");
80
81 if (pid == 0)
82 do_master_child();
83
84 tst_record_childstatus(cleanup, pid);
85
86 cleanup();
87 tst_exit();
88 }
89
90 /*
91 * do_master_child()
92 */
do_master_child(void)93 void do_master_child(void)
94 {
95 int lc;
96 int pid;
97 int status;
98
99 for (lc = 0; TEST_LOOPING(lc); lc++) {
100 int tst_fd;
101
102 /* Reset tst_count in case we are looping */
103 tst_count = 0;
104
105 if (SETRESUID(NULL, 0, ltpuser->pw_uid, 0) == -1) {
106 perror("setresuid failed");
107 exit(TFAIL);
108 }
109
110 /* Test 1: Check the process with new uid cannot open the file
111 * with RDWR permissions.
112 */
113 TEST(tst_fd = open(testfile, O_RDWR));
114
115 if (TEST_RETURN != -1) {
116 printf("open succeeded unexpectedly\n");
117 close(tst_fd);
118 exit(TFAIL);
119 }
120
121 if (TEST_ERRNO == EACCES) {
122 printf("open failed with EACCES as expected\n");
123 } else {
124 perror("open failed unexpectedly");
125 exit(TFAIL);
126 }
127
128 /* Test 2: Check a son process cannot open the file
129 * with RDWR permissions.
130 */
131 pid = FORK_OR_VFORK();
132 if (pid < 0)
133 tst_brkm(TBROK, NULL, "Fork failed");
134
135 if (pid == 0) {
136 int tst_fd2;
137
138 /* Test to open the file in son process */
139 TEST(tst_fd2 = open(testfile, O_RDWR));
140
141 if (TEST_RETURN != -1) {
142 printf("call succeeded unexpectedly\n");
143 close(tst_fd2);
144 exit(TFAIL);
145 }
146
147 if (TEST_ERRNO == EACCES) {
148 printf("open failed with EACCES as expected\n");
149 exit(TPASS);
150 } else {
151 printf("open failed unexpectedly\n");
152 exit(TFAIL);
153 }
154 } else {
155 /* Wait for son completion */
156 if (waitpid(pid, &status, 0) == -1) {
157 perror("waitpid failed");
158 exit(TFAIL);
159 }
160
161 if (!WIFEXITED(status))
162 exit(TFAIL);
163
164 if (WEXITSTATUS(status) != TPASS)
165 exit(WEXITSTATUS(status));
166 }
167
168 /* Test 3: Fallback to initial uid and check we can again open
169 * the file with RDWR permissions.
170 */
171 tst_count++;
172 if (SETRESUID(NULL, 0, 0, 0) == -1) {
173 perror("setresuid failed");
174 exit(TFAIL);
175 }
176
177 TEST(tst_fd = open(testfile, O_RDWR));
178
179 if (TEST_RETURN == -1) {
180 perror("open failed unexpectedly");
181 exit(TFAIL);
182 } else {
183 printf("open call succeeded\n");
184 close(tst_fd);
185 }
186 }
187 exit(TPASS);
188 }
189
190 /*
191 * setup() - performs all ONE TIME setup for this test
192 */
setup(void)193 void setup(void)
194 {
195 tst_require_root();
196
197 ltpuser = getpwnam(nobody_uid);
198
199 UID16_CHECK(ltpuser->pw_uid, "setresuid", cleanup)
200
201 tst_tmpdir();
202
203 sprintf(testfile, "setresuid04file%d.tst", getpid());
204
205 /* Create test file */
206 fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644);
207
208 tst_sig(FORK, DEF_HANDLER, cleanup);
209
210 TEST_PAUSE;
211 }
212
213 /*
214 * cleanup() - performs all the ONE TIME cleanup for this test at completion
215 * or premature exit
216 */
cleanup(void)217 void cleanup(void)
218 {
219 close(fd);
220
221 tst_rmdir();
222
223 }
224