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 <pwd.h>
55 #include "compat_16.h"
56
57 TCID_DEFINE(setresuid04);
58 int TST_TOTAL = 1;
59 char nobody_uid[] = "nobody";
60 char testfile[256] = "";
61 struct passwd *ltpuser;
62
63 int fd = -1;
64
65 void setup(void);
66 void cleanup(void);
67 void do_master_child();
68
main(int ac,char ** av)69 int main(int ac, char **av)
70 {
71 pid_t pid;
72
73 tst_parse_opts(ac, av, NULL, NULL);
74 setup();
75
76 pid = FORK_OR_VFORK();
77 if (pid < 0)
78 tst_brkm(TBROK, cleanup, "Fork failed");
79
80 if (pid == 0)
81 do_master_child();
82
83 tst_record_childstatus(cleanup, pid);
84
85 cleanup();
86 tst_exit();
87 }
88
89 /*
90 * do_master_child()
91 */
do_master_child(void)92 void do_master_child(void)
93 {
94 int lc;
95 int pid;
96 int status;
97
98 for (lc = 0; TEST_LOOPING(lc); lc++) {
99 int tst_fd;
100
101 /* Reset tst_count in case we are looping */
102 tst_count = 0;
103
104 if (SETRESUID(NULL, 0, ltpuser->pw_uid, 0) == -1) {
105 perror("setresuid failed");
106 exit(TFAIL);
107 }
108
109 /* Test 1: Check the process with new uid cannot open the file
110 * with RDWR permissions.
111 */
112 TEST(tst_fd = open(testfile, O_RDWR));
113
114 if (TEST_RETURN != -1) {
115 printf("open succeeded unexpectedly\n");
116 close(tst_fd);
117 exit(TFAIL);
118 }
119
120 if (TEST_ERRNO == EACCES) {
121 printf("open failed with EACCES as expected\n");
122 } else {
123 perror("open failed unexpectedly");
124 exit(TFAIL);
125 }
126
127 /* Test 2: Check a son process cannot open the file
128 * with RDWR permissions.
129 */
130 pid = FORK_OR_VFORK();
131 if (pid < 0)
132 tst_brkm(TBROK, NULL, "Fork failed");
133
134 if (pid == 0) {
135 int tst_fd2;
136
137 /* Test to open the file in son process */
138 TEST(tst_fd2 = open(testfile, O_RDWR));
139
140 if (TEST_RETURN != -1) {
141 printf("call succeeded unexpectedly\n");
142 close(tst_fd2);
143 exit(TFAIL);
144 }
145
146 if (TEST_ERRNO == EACCES) {
147 printf("open failed with EACCES as expected\n");
148 exit(TPASS);
149 } else {
150 printf("open failed unexpectedly\n");
151 exit(TFAIL);
152 }
153 } else {
154 /* Wait for son completion */
155 if (waitpid(pid, &status, 0) == -1) {
156 perror("waitpid failed");
157 exit(TFAIL);
158 }
159
160 if (!WIFEXITED(status))
161 exit(TFAIL);
162
163 if (WEXITSTATUS(status) != TPASS)
164 exit(WEXITSTATUS(status));
165 }
166
167 /* Test 3: Fallback to initial uid and check we can again open
168 * the file with RDWR permissions.
169 */
170 tst_count++;
171 if (SETRESUID(NULL, 0, 0, 0) == -1) {
172 perror("setresuid failed");
173 exit(TFAIL);
174 }
175
176 TEST(tst_fd = open(testfile, O_RDWR));
177
178 if (TEST_RETURN == -1) {
179 perror("open failed unexpectedly");
180 exit(TFAIL);
181 } else {
182 printf("open call succeeded\n");
183 close(tst_fd);
184 }
185 }
186 exit(TPASS);
187 }
188
189 /*
190 * setup() - performs all ONE TIME setup for this test
191 */
setup(void)192 void setup(void)
193 {
194 tst_require_root();
195
196 ltpuser = getpwnam(nobody_uid);
197
198 UID16_CHECK(ltpuser->pw_uid, "setresuid", cleanup)
199
200 tst_tmpdir();
201
202 sprintf(testfile, "setresuid04file%d.tst", getpid());
203
204 /* Create test file */
205 fd = open(testfile, O_CREAT | O_RDWR, 0644);
206 if (fd < 0)
207 tst_brkm(TBROK, cleanup, "cannot creat test file");
208
209 tst_sig(FORK, DEF_HANDLER, cleanup);
210
211 TEST_PAUSE;
212 }
213
214 /*
215 * cleanup() - performs all the ONE TIME cleanup for this test at completion
216 * or premature exit
217 */
cleanup(void)218 void cleanup(void)
219 {
220 close(fd);
221
222 tst_rmdir();
223
224 }
225