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 setuid behaves correctly with file permissions. The test creates a
23 * file as ROOT with permissions 0644, does a setuid and then tries to open the
24 * file with RDWR permissions. The same test is done in a fork to check if new
25 * UIDs are correctly passed to the son.
26 */
27
28 #include <errno.h>
29 #include <pwd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35
36 #include "test.h"
37 #include "safe_macros.h"
38 #include "compat_16.h"
39
40 char *TCID = "setuid04";
41 int TST_TOTAL = 1;
42
43 static char nobody_uid[] = "nobody";
44 static char testfile[] = "setuid04_testfile";
45 static struct passwd *ltpuser;
46
47 static int fd = -1;
48
49 static void setup(void);
50 static void cleanup(void);
51 static void do_master_child(void);
52
main(int ac,char ** av)53 int main(int ac, char **av)
54 {
55 pid_t pid;
56 int status;
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 } else {
69 waitpid(pid, &status, 0);
70 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
71 tst_resm(WEXITSTATUS(status),
72 "son process exits with error");
73 }
74
75 cleanup();
76 tst_exit();
77 }
78
do_master_child(void)79 static void do_master_child(void)
80 {
81 int lc;
82 int pid;
83 int status;
84
85 if (SETUID(NULL, ltpuser->pw_uid) == -1) {
86 tst_brkm(TBROK, NULL,
87 "setuid failed to set the effective uid to %d",
88 ltpuser->pw_uid);
89 }
90
91 for (lc = 0; TEST_LOOPING(lc); lc++) {
92 int tst_fd;
93
94 tst_count = 0;
95
96 TEST(tst_fd = open(testfile, O_RDWR));
97
98 if (TEST_RETURN != -1) {
99 tst_resm(TFAIL, "call succeeded unexpectedly");
100 close(tst_fd);
101 }
102
103 if (TEST_ERRNO == EACCES) {
104 tst_resm(TPASS, "open returned errno EACCES");
105 } else {
106 tst_resm(TFAIL, "open returned unexpected errno - %d",
107 TEST_ERRNO);
108 continue;
109 }
110
111 pid = FORK_OR_VFORK();
112 if (pid < 0)
113 tst_brkm(TBROK, NULL, "Fork failed");
114
115 if (pid == 0) {
116 int tst_fd2;
117
118 /* Test to open the file in son process */
119 TEST(tst_fd2 = open(testfile, O_RDWR));
120
121 if (TEST_RETURN != -1) {
122 tst_resm(TFAIL, "call succeeded unexpectedly");
123 close(tst_fd2);
124 }
125
126 if (TEST_ERRNO == EACCES) {
127 tst_resm(TPASS, "open returned errno EACCES");
128 } else {
129 tst_resm(TFAIL,
130 "open returned unexpected errno - %d",
131 TEST_ERRNO);
132 }
133 tst_exit();
134 } else {
135 /* Wait for son completion */
136 waitpid(pid, &status, 0);
137 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
138 exit(WEXITSTATUS(status));
139 }
140 }
141 tst_exit();
142 }
143
setup(void)144 static void setup(void)
145 {
146 tst_require_root();
147
148 ltpuser = getpwnam(nobody_uid);
149
150 if (ltpuser == NULL)
151 tst_brkm(TBROK, cleanup, "getpwnam failed for user id %s",
152 nobody_uid);
153
154 UID16_CHECK(ltpuser->pw_uid, setuid, cleanup);
155
156 tst_tmpdir();
157
158 /* Create test file */
159 fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644);
160
161 tst_sig(FORK, DEF_HANDLER, cleanup);
162
163 TEST_PAUSE;
164 }
165
cleanup(void)166 static void cleanup(void)
167 {
168 close(fd);
169 tst_rmdir();
170 }
171