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