1 /*
2 * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15 *
16 */
17 /**********************************************************
18 *
19 * TEST IDENTIFIER : capset02
20 *
21 * EXECUTED BY : anyone
22 *
23 * TEST TITLE : Tests for error conditions.
24 *
25 * TEST CASE TOTAL : 4
26 *
27 * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com>
28 *
29 * SIGNALS
30 * Uses SIGUSR1 to pause before test if option set.
31 * (See the parse_opts(3) man page).
32 *
33 * DESCRIPTION
34 * Verify that
35 * 1) capset() fails with errno set to EFAULT if an invalid address
36 * is given for header
37 * 2) capset() fails with errno set to EFAULT if an invalid address
38 * is given for data
39 * 3) capset() fails with errno set to EINVAL if an invalid value
40 * is given for header->version
41 * 4) capset() fails with errno set to EPERM the process does not
42 * have enough privilege to set capabilities
43 *
44 *
45 * Setup:
46 * Setup signal handling.
47 * Pause for SIGUSR1 if option specified.
48 * Call capget() to save current capability data
49 *
50 * Test:
51 * Loop if the proper options are given.
52 * do test specific setup.
53 * call capset with proper arguments
54 * if capset() fails with expected errno
55 * Test passed
56 * Otherwise
57 * Test failed
58 * do test specific cleanup
59 *
60 * Cleanup:
61 * Print errno log and/or timing stats if options given
62 *
63 * USAGE: <for command-line>
64 * capset02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] [-h] [-f] [-p]
65 * where, -c n : Run n copies concurrently.
66 * -e : Turn on errno logging.
67 * -h : Show help screen
68 * -f : Turn off functional testing
69 * -i n : Execute test n times.
70 * -I x : Execute test for x seconds.
71 * -p : Pause for SIGUSR1 before starting
72 * -P x : Pause for x seconds between iterations.
73 * -t : Turn on syscall timing.
74 *
75 ****************************************************************/
76 #include <sys/types.h>
77 #include <sys/wait.h>
78 #include <errno.h>
79 #include <pwd.h>
80 #include <signal.h>
81 #include <string.h>
82 #include <unistd.h>
83 #include "test.h"
84 #include "linux_syscall_numbers.h"
85
86 /**************************************************************************/
87 /* */
88 /* Some archs do not have the manpage documented sys/capability.h file, */
89 /* and require the use of the line below */
90
91 #include <linux/capability.h>
92
93 /* If you are having issues with including this file and have the sys/ */
94 /* version, then you may want to try switching to it. -Robbie W. */
95 /**************************************************************************/
96
97 #define INVALID_VERSION 0
98
99 static void setup(void);
100 static void cleanup(void);
101 static void test_setup(int, char *);
102 static void child_func(void);
103
104 static pid_t child_pid = -1;
105
106 char *TCID = "capset02";
107
108 static struct __user_cap_header_struct header;
109 static struct __user_cap_data_struct data;
110
111 struct test_case_t {
112 cap_user_header_t headerp;
113 cap_user_data_t datap;
114 int exp_errno;
115 char *errdesc;
116 } test_cases[] = {
117 #ifndef UCLINUX
118 /* Skip since uClinux does not implement memory protection */
119 {
120 (cap_user_header_t) - 1, &data, EFAULT, "EFAULT"}, {
121 &header, (cap_user_data_t) - 1, EFAULT, "EFAULT"},
122 #endif
123 {
124 &header, &data, EINVAL, "EINVAL"}, {
125 &header, &data, EPERM, "EPERM"},};
126
127 int TST_TOTAL = sizeof(test_cases) / sizeof(test_cases[0]);
128
main(int ac,char ** av)129 int main(int ac, char **av)
130 {
131
132 int lc, i;
133
134 tst_parse_opts(ac, av, NULL, NULL);
135 #ifdef UCLINUX
136 maybe_run_child(&child_func, "");
137 #endif
138
139 setup();
140
141 for (lc = 0; TEST_LOOPING(lc); lc++) {
142
143 tst_count = 0;
144
145 #ifdef UCLINUX
146 i = 2;
147 #else
148 i = 0;
149 #endif
150
151 for (; i < TST_TOTAL; i++) {
152
153 test_setup(i, av[0]);
154 TEST(ltp_syscall(__NR_capset, test_cases[i].headerp,
155 test_cases[i].datap));
156
157 if (TEST_RETURN == -1 &&
158 TEST_ERRNO == test_cases[i].exp_errno) {
159 tst_resm(TPASS, "capset() returned -1,"
160 " errno: %s", test_cases[i].errdesc);
161 } else {
162 tst_resm(TFAIL | TTERRNO,
163 "Test Failed, capset() returned %ld",
164 TEST_RETURN);
165 }
166 }
167 }
168
169 cleanup();
170
171 tst_exit();
172
173 }
174
setup(void)175 void setup(void)
176 {
177 tst_require_root();
178
179 TEST_PAUSE;
180
181 /*
182 * Save current capability data.
183 * header.version must be _LINUX_CAPABILITY_VERSION
184 */
185 header.version = _LINUX_CAPABILITY_VERSION;
186 if (ltp_syscall(__NR_capget, &header, &data) == -1)
187 tst_brkm(TBROK | TERRNO, NULL, "capget failed");
188 }
189
cleanup(void)190 void cleanup(void)
191 {
192 if (0 < child_pid) {
193 kill(child_pid, SIGTERM);
194 wait(NULL);
195 }
196 }
197
child_func(void)198 void child_func(void)
199 {
200 for (;;) {
201 sleep(10);
202 }
203 }
204
test_setup(int i,char * argv0)205 void test_setup(int i, char *argv0)
206 {
207 char nobody_uid[] = "nobody";
208 struct passwd *ltpuser;
209
210 switch (i) {
211 case 0:
212 break;
213
214 case 1:
215 header.version = _LINUX_CAPABILITY_VERSION;
216 header.pid = 0;
217 break;
218
219 case 2:
220 header.version = INVALID_VERSION;
221 header.pid = 0;
222 break;
223
224 case 3:
225 header.version = _LINUX_CAPABILITY_VERSION;
226 /*
227 * when a non-zero pid is specified, process should have
228 * CAP_SETPCAP capability to change capabilities.
229 * by default, CAP_SETPCAP is not enabled. So giving
230 * a non-zero pid results in capset() failing with
231 * errno EPERM
232 *
233 * Note: this seems to have changed with recent kernels
234 * => create a child and try to set its capabilities
235 */
236 child_pid = FORK_OR_VFORK();
237 if (child_pid == -1)
238 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
239 else if (child_pid == 0) {
240 #ifdef UCLINUX
241 if (self_exec(argv0, "") < 0) {
242 perror("self_exec failed");
243 exit(1);
244 }
245 #else
246 child_func();
247 #endif
248 } else {
249 header.pid = child_pid;
250 ltpuser = getpwnam(nobody_uid);
251 if (ltpuser == NULL)
252 tst_brkm(TBROK | TERRNO, cleanup,
253 "getpwnam failed");
254 if (seteuid(ltpuser->pw_uid) == -1)
255 tst_brkm(TBROK | TERRNO, cleanup,
256 "seteuid failed");
257
258 }
259 break;
260
261 }
262 }
263