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 "compat_16.h"
42
43 TCID_DEFINE(setfsuid04);
44 int TST_TOTAL = 1;
45
46 static char nobody_uid[] = "nobody";
47 static char testfile[] = "setfsuid04_testfile";
48 static struct passwd *ltpuser;
49
50 static int fd = -1;
51
52 static void setup(void);
53 static void cleanup(void);
54 static void do_master_child(void);
55
main(int ac,char ** av)56 int main(int ac, char **av)
57 {
58 pid_t pid;
59
60 tst_parse_opts(ac, av, NULL, NULL);
61
62 setup();
63
64 pid = FORK_OR_VFORK();
65 if (pid < 0)
66 tst_brkm(TBROK, cleanup, "Fork failed");
67
68 if (pid == 0)
69 do_master_child();
70
71 tst_record_childstatus(cleanup, pid);
72
73 cleanup();
74 tst_exit();
75 }
76
do_master_child(void)77 static void do_master_child(void)
78 {
79 int pid;
80 int status;
81
82 if (SETFSUID(NULL, ltpuser->pw_uid) == -1) {
83 perror("setfsuid failed");
84 exit(TFAIL);
85 }
86
87 /* Test 1: Check the process with new uid cannot open the file
88 * with RDWR permissions.
89 */
90 TEST(open(testfile, O_RDWR));
91
92 if (TEST_RETURN != -1) {
93 close(TEST_RETURN);
94 printf("open succeeded unexpectedly\n");
95 exit(TFAIL);
96 }
97
98 if (TEST_ERRNO == EACCES) {
99 printf("open failed with EACCESS as expected\n");
100 } else {
101 printf("open returned unexpected errno - %d\n", TEST_ERRNO);
102 exit(TFAIL);
103 }
104
105 /* Test 2: Check a son process cannot open the file
106 * with RDWR permissions.
107 */
108 pid = FORK_OR_VFORK();
109 if (pid < 0) {
110 perror("Fork failed");
111 exit(TFAIL);
112 }
113
114 if (pid == 0) {
115 /* Test to open the file in son process */
116 TEST(open(testfile, O_RDWR));
117
118 if (TEST_RETURN != -1) {
119 close(TEST_RETURN);
120 printf("open succeeded unexpectedly\n");
121 exit(TFAIL);
122 }
123
124 if (TEST_ERRNO == EACCES) {
125 printf("open failed with EACCESS as expected\n");
126 } else {
127 printf("open returned unexpected errno - %d\n",
128 TEST_ERRNO);
129 exit(TFAIL);
130 }
131 } else {
132 /* Wait for son completion */
133 if (waitpid(pid, &status, 0) == -1) {
134 perror("waitpid failed");
135 exit(TFAIL);
136 }
137
138 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
139 exit(WEXITSTATUS(status));
140 }
141
142 /* Test 3: Fallback to initial uid and check we can again open
143 * the file with RDWR permissions.
144 */
145 tst_count++;
146 if (SETFSUID(NULL, 0) == -1) {
147 perror("setfsuid failed");
148 exit(TFAIL);
149 }
150
151 TEST(open(testfile, O_RDWR));
152
153 if (TEST_RETURN == -1) {
154 perror("open failed unexpectedly");
155 exit(TFAIL);
156 } else {
157 printf("open call succeeded\n");
158 close(TEST_RETURN);
159 }
160 exit(TPASS);
161 }
162
setup(void)163 static void setup(void)
164 {
165 tst_require_root();
166
167 ltpuser = getpwnam(nobody_uid);
168 if (ltpuser == NULL)
169 tst_brkm(TBROK, cleanup, "getpwnam failed for user id %s",
170 nobody_uid);
171
172 UID16_CHECK(ltpuser->pw_uid, setfsuid, cleanup);
173
174 tst_tmpdir();
175
176 /* Create test file */
177 fd = open(testfile, O_CREAT | O_RDWR, 0644);
178 if (fd < 0)
179 tst_brkm(TBROK, cleanup, "cannot creat test file");
180
181 tst_sig(FORK, DEF_HANDLER, cleanup);
182
183 TEST_PAUSE;
184 }
185
cleanup(void)186 static void cleanup(void)
187 {
188 close(fd);
189 tst_rmdir();
190 }
191