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 "safe_macros.h"
85 #include "lapi/syscalls.h"
86
87 /**************************************************************************/
88 /* */
89 /* Some archs do not have the manpage documented sys/capability.h file, */
90 /* and require the use of the line below */
91
92 #include <linux/capability.h>
93
94 /* If you are having issues with including this file and have the sys/ */
95 /* version, then you may want to try switching to it. -Robbie W. */
96 /**************************************************************************/
97
98 #define INVALID_VERSION 0
99
100 static void setup(void);
101 static void cleanup(void);
102 static void test_setup(int, char *);
103 static void child_func(void);
104
105 static pid_t child_pid = -1;
106
107 char *TCID = "capset02";
108
109 static struct __user_cap_header_struct header;
110 static struct __user_cap_data_struct data;
111
112 struct test_case_t {
113 cap_user_header_t headerp;
114 cap_user_data_t datap;
115 int exp_errno;
116 char *errdesc;
117 } test_cases[] = {
118 #ifndef UCLINUX
119 /* Skip since uClinux does not implement memory protection */
120 {
121 (cap_user_header_t) - 1, &data, EFAULT, "EFAULT"}, {
122 &header, (cap_user_data_t) - 1, EFAULT, "EFAULT"},
123 #endif
124 {
125 &header, &data, EINVAL, "EINVAL"}, {
126 &header, &data, EPERM, "EPERM"},};
127
128 int TST_TOTAL = sizeof(test_cases) / sizeof(test_cases[0]);
129
main(int ac,char ** av)130 int main(int ac, char **av)
131 {
132
133 int lc, i;
134
135 tst_parse_opts(ac, av, NULL, NULL);
136 #ifdef UCLINUX
137 maybe_run_child(&child_func, "");
138 #endif
139
140 setup();
141
142 for (lc = 0; TEST_LOOPING(lc); lc++) {
143
144 tst_count = 0;
145
146 #ifdef UCLINUX
147 i = 2;
148 #else
149 i = 0;
150 #endif
151
152 for (; i < TST_TOTAL; i++) {
153
154 test_setup(i, av[0]);
155 TEST(ltp_syscall(__NR_capset, test_cases[i].headerp,
156 test_cases[i].datap));
157
158 if (TEST_RETURN == -1 &&
159 TEST_ERRNO == test_cases[i].exp_errno) {
160 tst_resm(TPASS, "capset() returned -1,"
161 " errno: %s", test_cases[i].errdesc);
162 } else {
163 tst_resm(TFAIL | TTERRNO,
164 "Test Failed, capset() returned %ld",
165 TEST_RETURN);
166 }
167 }
168 }
169
170 cleanup();
171
172 tst_exit();
173
174 }
175
setup(void)176 void setup(void)
177 {
178 tst_require_root();
179
180 TEST_PAUSE;
181
182 /*
183 * Save current capability data.
184 * header.version must be _LINUX_CAPABILITY_VERSION
185 */
186 header.version = _LINUX_CAPABILITY_VERSION;
187 if (ltp_syscall(__NR_capget, &header, &data) == -1)
188 tst_brkm(TBROK | TERRNO, NULL, "capget failed");
189 }
190
cleanup(void)191 void cleanup(void)
192 {
193 if (0 < child_pid) {
194 kill(child_pid, SIGTERM);
195 wait(NULL);
196 }
197 }
198
child_func(void)199 void child_func(void)
200 {
201 for (;;) {
202 sleep(10);
203 }
204 }
205
test_setup(int i,char * argv0)206 void test_setup(int i, char *argv0)
207 {
208 char nobody_uid[] = "nobody";
209 struct passwd *ltpuser;
210
211 switch (i) {
212 case 0:
213 break;
214
215 case 1:
216 header.version = _LINUX_CAPABILITY_VERSION;
217 header.pid = 0;
218 break;
219
220 case 2:
221 header.version = INVALID_VERSION;
222 header.pid = 0;
223 break;
224
225 case 3:
226 header.version = _LINUX_CAPABILITY_VERSION;
227 /*
228 * when a non-zero pid is specified, process should have
229 * CAP_SETPCAP capability to change capabilities.
230 * by default, CAP_SETPCAP is not enabled. So giving
231 * a non-zero pid results in capset() failing with
232 * errno EPERM
233 *
234 * Note: this seems to have changed with recent kernels
235 * => create a child and try to set its capabilities
236 */
237 child_pid = FORK_OR_VFORK();
238 if (child_pid == -1)
239 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
240 else if (child_pid == 0) {
241 #ifdef UCLINUX
242 if (self_exec(argv0, "") < 0) {
243 perror("self_exec failed");
244 exit(1);
245 }
246 #else
247 child_func();
248 #endif
249 } else {
250 header.pid = child_pid;
251 ltpuser = getpwnam(nobody_uid);
252 if (ltpuser == NULL)
253 tst_brkm(TBROK | TERRNO, cleanup,
254 "getpwnam failed");
255 SAFE_SETEUID(cleanup, ltpuser->pw_uid);
256
257 }
258 break;
259
260 }
261 }
262