1 |
/* |
2 |
* ccs_new_capability_test.c |
3 |
* |
4 |
* Copyright (C) 2005-2012 NTT DATA CORPORATION |
5 |
* |
6 |
* Version: 1.8.3+ 2015/04/21 |
7 |
* |
8 |
* This program is free software; you can redistribute it and/or modify it |
9 |
* under the terms of the GNU General Public License v2 as published by the |
10 |
* Free Software Foundation. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, but WITHOUT |
13 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 |
* more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License along with |
18 |
* this program; if not, write to the Free Software Foundation, Inc., |
19 |
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
20 |
*/ |
21 |
#include "include.h" |
22 |
|
23 |
static const char *capability = ""; |
24 |
|
25 |
static int write_policy(void) |
26 |
{ |
27 |
FILE *fp = fopen(proc_policy_domain_policy, "r"); |
28 |
char buffer[8192]; |
29 |
int domain_found = 0; |
30 |
int policy_found = 0; |
31 |
memset(buffer, 0, sizeof(buffer)); |
32 |
fprintf(domain_fp, "capability %s\n", capability); |
33 |
fflush(domain_fp); |
34 |
if (!fp) { |
35 |
printf("capability %s : BUG: capability read failed\n", |
36 |
capability); |
37 |
return 0; |
38 |
} |
39 |
while (fgets(buffer, sizeof(buffer) - 1, fp)) { |
40 |
char *cp = strchr(buffer, '\n'); |
41 |
if (cp) |
42 |
*cp = '\0'; |
43 |
if (!strncmp(buffer, "<kernel>", 8)) |
44 |
domain_found = !strcmp(self_domain, buffer); |
45 |
if (!domain_found) |
46 |
continue; |
47 |
if (!strncmp(buffer, "capability ", 11) && |
48 |
!strcmp(buffer + 11, capability)) { |
49 |
policy_found = 1; |
50 |
break; |
51 |
} |
52 |
} |
53 |
fclose(fp); |
54 |
if (!policy_found) { |
55 |
printf("capability %s : BUG: capability write failed\n", |
56 |
capability); |
57 |
return 0; |
58 |
} |
59 |
errno = 0; |
60 |
return 1; |
61 |
} |
62 |
|
63 |
static void delete_policy(void) |
64 |
{ |
65 |
fprintf(domain_fp, "delete capability %s\n", |
66 |
capability); |
67 |
fflush(domain_fp); |
68 |
} |
69 |
|
70 |
static void show_result(int result, char should_success) |
71 |
{ |
72 |
int err = errno; |
73 |
printf("capability %s : ", capability); |
74 |
if (should_success) { |
75 |
if (result != EOF) |
76 |
printf("OK\n"); |
77 |
else |
78 |
printf("FAILED: %s\n", strerror(err)); |
79 |
} else { |
80 |
if (result == EOF) { |
81 |
if (err == EPERM) |
82 |
printf("OK: Permission denied.\n"); |
83 |
else |
84 |
printf("FAILED: %s\n", strerror(err)); |
85 |
} else { |
86 |
printf("BUG\n"); |
87 |
} |
88 |
} |
89 |
} |
90 |
|
91 |
static void set_capability(void) |
92 |
{ |
93 |
char buffer[128]; |
94 |
memset(buffer, 0, sizeof(buffer)); |
95 |
snprintf(buffer, sizeof(buffer) - 1, "capability::%s", capability); |
96 |
set_profile(3, buffer); |
97 |
} |
98 |
|
99 |
static void unset_capability(void) |
100 |
{ |
101 |
char buffer[128]; |
102 |
memset(buffer, 0, sizeof(buffer)); |
103 |
snprintf(buffer, sizeof(buffer) - 1, "capability::%s", capability); |
104 |
set_profile(0, buffer); |
105 |
} |
106 |
|
107 |
static void stage_capability_test(void) |
108 |
{ |
109 |
char tmp1[128]; |
110 |
char tmp2[128]; |
111 |
int ret_ignored; |
112 |
memset(tmp1, 0, sizeof(tmp1)); |
113 |
memset(tmp2, 0, sizeof(tmp2)); |
114 |
|
115 |
capability = "use_route"; |
116 |
set_capability(); |
117 |
if (write_policy()) { |
118 |
int fd = socket(AF_ROUTE, SOCK_RAW, 0); |
119 |
show_result(fd, 1); |
120 |
if (fd != EOF) |
121 |
close(fd); |
122 |
delete_policy(); |
123 |
fd = socket(AF_ROUTE, SOCK_RAW, 0); |
124 |
show_result(fd, 0); |
125 |
if (fd != EOF) |
126 |
close(fd); |
127 |
} |
128 |
unset_capability(); |
129 |
|
130 |
capability = "use_packet"; |
131 |
set_capability(); |
132 |
if (write_policy()) { |
133 |
int fd = socket(AF_PACKET, SOCK_RAW, 0); |
134 |
show_result(fd, 1); |
135 |
if (fd != EOF) |
136 |
close(fd); |
137 |
delete_policy(); |
138 |
fd = socket(AF_PACKET, SOCK_RAW, 0); |
139 |
show_result(fd, 0); |
140 |
if (fd != EOF) |
141 |
close(fd); |
142 |
} |
143 |
unset_capability(); |
144 |
|
145 |
capability = "use_kernel_module"; |
146 |
set_capability(); |
147 |
if (write_policy()) { |
148 |
if (!is_kernel26) |
149 |
show_result((long) create_module("", 0), 1); |
150 |
show_result(init_module("", NULL), 1); |
151 |
show_result(delete_module(""), 1); |
152 |
delete_policy(); |
153 |
if (!is_kernel26) |
154 |
show_result((long) create_module("", 0), 0); |
155 |
show_result(init_module("", NULL), 0); |
156 |
show_result(delete_module(""), 0); |
157 |
} |
158 |
unset_capability(); |
159 |
|
160 |
capability = "SYS_REBOOT"; |
161 |
set_capability(); |
162 |
if (write_policy()) { |
163 |
FILE *fp = fopen("/proc/sys/kernel/ctrl-alt-del", "a+"); |
164 |
unsigned int c; |
165 |
if (fp && fscanf(fp, "%u", &c) == 1) { |
166 |
show_result(reboot(LINUX_REBOOT_CMD_CAD_ON), 1); |
167 |
delete_policy(); |
168 |
show_result(reboot(LINUX_REBOOT_CMD_CAD_ON), 0); |
169 |
rewind(fp); |
170 |
fprintf(fp, "%u\n", c); |
171 |
} else { |
172 |
/* Use invalid value */ |
173 |
show_result(reboot(0x0000C0DE), 1); |
174 |
delete_policy(); |
175 |
show_result(reboot(0x0000C0DE), 0); |
176 |
} |
177 |
if (fp) |
178 |
fclose(fp); |
179 |
} |
180 |
unset_capability(); |
181 |
|
182 |
capability = "SYS_KEXEC_LOAD"; |
183 |
set_capability(); |
184 |
if (write_policy()) { |
185 |
#ifdef __NR_sys_kexec_load |
186 |
if (is_kernel26) |
187 |
show_result(sys_kexec_load(0, 0, NULL, 0), 1); |
188 |
#endif |
189 |
delete_policy(); |
190 |
#ifdef __NR_sys_kexec_load |
191 |
if (is_kernel26) |
192 |
show_result(sys_kexec_load(0, 0, NULL, 0), 0); |
193 |
#endif |
194 |
} |
195 |
unset_capability(); |
196 |
|
197 |
capability = "SYS_VHANGUP"; |
198 |
set_capability(); |
199 |
if (write_policy()) { |
200 |
int status = 0; |
201 |
int pipe_fd[2] = { EOF, EOF }; |
202 |
ret_ignored = pipe(pipe_fd); |
203 |
switch (fork()) { |
204 |
case 0: |
205 |
setsid(); |
206 |
errno = 0; |
207 |
vhangup(); |
208 |
status = errno; |
209 |
ret_ignored = write(pipe_fd[1], &status, |
210 |
sizeof(status)); |
211 |
_exit(0); |
212 |
case -1: |
213 |
fprintf(stderr, "fork() failed.\n"); |
214 |
break; |
215 |
default: |
216 |
close(pipe_fd[1]); |
217 |
ret_ignored = read(pipe_fd[0], &status, sizeof(status)); |
218 |
wait(NULL); |
219 |
close(pipe_fd[0]); |
220 |
errno = status; |
221 |
show_result(status ? EOF : 0, 1); |
222 |
} |
223 |
delete_policy(); |
224 |
status = 0; |
225 |
ret_ignored = pipe(pipe_fd); |
226 |
switch (fork()) { |
227 |
case 0: |
228 |
errno = 0; |
229 |
setsid(); |
230 |
vhangup(); |
231 |
status = errno; |
232 |
ret_ignored = write(pipe_fd[1], &status, |
233 |
sizeof(status)); |
234 |
_exit(0); |
235 |
case -1: |
236 |
fprintf(stderr, "fork() failed.\n"); |
237 |
break; |
238 |
default: |
239 |
close(pipe_fd[1]); |
240 |
ret_ignored = read(pipe_fd[0], &status, sizeof(status)); |
241 |
wait(NULL); |
242 |
close(pipe_fd[0]); |
243 |
errno = status; |
244 |
show_result(status ? EOF : 0, 0); |
245 |
} |
246 |
} |
247 |
unset_capability(); |
248 |
|
249 |
capability = "SYS_TIME"; |
250 |
set_capability(); |
251 |
if (write_policy()) { |
252 |
struct timeval tv; |
253 |
struct timezone tz; |
254 |
struct timex buf; |
255 |
time_t now = time(NULL); |
256 |
show_result(stime(&now), 1); |
257 |
gettimeofday(&tv, &tz); |
258 |
show_result(settimeofday(&tv, &tz), 1); |
259 |
memset(&buf, 0, sizeof(buf)); |
260 |
buf.modes = 0x100; /* Use invalid value so that the clock |
261 |
won't change. */ |
262 |
show_result(adjtimex(&buf), 1); |
263 |
delete_policy(); |
264 |
now = time(NULL); |
265 |
show_result(stime(&now), 0); |
266 |
gettimeofday(&tv, &tz); |
267 |
show_result(settimeofday(&tv, &tz), 0); |
268 |
memset(&buf, 0, sizeof(buf)); |
269 |
buf.modes = 0x100; /* Use invalid value so that the clock |
270 |
won't change. */ |
271 |
show_result(adjtimex(&buf), 0); |
272 |
} |
273 |
unset_capability(); |
274 |
|
275 |
capability = "SYS_NICE"; |
276 |
set_capability(); |
277 |
if (write_policy()) { |
278 |
show_result(nice(0), 1); |
279 |
show_result(setpriority(PRIO_PROCESS, pid, |
280 |
getpriority(PRIO_PROCESS, pid)), 1); |
281 |
delete_policy(); |
282 |
show_result(nice(0), 0); |
283 |
show_result(setpriority(PRIO_PROCESS, pid, |
284 |
getpriority(PRIO_PROCESS, pid)), 0); |
285 |
} |
286 |
unset_capability(); |
287 |
|
288 |
capability = "SYS_SETHOSTNAME"; |
289 |
set_capability(); |
290 |
if (write_policy()) { |
291 |
char buffer[4096]; |
292 |
memset(buffer, 0, sizeof(buffer)); |
293 |
gethostname(buffer, sizeof(buffer) - 1); |
294 |
show_result(sethostname(buffer, strlen(buffer)), 1); |
295 |
ret_ignored = getdomainname(buffer, sizeof(buffer) - 1); |
296 |
show_result(setdomainname(buffer, strlen(buffer)), 1); |
297 |
delete_policy(); |
298 |
gethostname(buffer, sizeof(buffer) - 1); |
299 |
show_result(sethostname(buffer, strlen(buffer)), 0); |
300 |
ret_ignored = getdomainname(buffer, sizeof(buffer) - 1); |
301 |
show_result(setdomainname(buffer, strlen(buffer)), 0); |
302 |
} |
303 |
unset_capability(); |
304 |
|
305 |
capability = "SYS_PTRACE"; |
306 |
set_capability(); |
307 |
if (write_policy()) { |
308 |
int status = 0; |
309 |
int pipe_fd[2] = { EOF, EOF }; |
310 |
ret_ignored = pipe(pipe_fd); |
311 |
switch (fork()) { |
312 |
case 0: |
313 |
errno = 0; |
314 |
ptrace(PTRACE_TRACEME, 0, NULL, NULL); |
315 |
status = errno; |
316 |
ret_ignored = write(pipe_fd[1], &status, |
317 |
sizeof(status)); |
318 |
_exit(0); |
319 |
case -1: |
320 |
fprintf(stderr, "fork() failed.\n"); |
321 |
break; |
322 |
default: |
323 |
close(pipe_fd[1]); |
324 |
ret_ignored = read(pipe_fd[0], &status, sizeof(status)); |
325 |
wait(NULL); |
326 |
close(pipe_fd[0]); |
327 |
errno = status; |
328 |
show_result(status ? EOF : 0, 1); |
329 |
} |
330 |
delete_policy(); |
331 |
status = 0; |
332 |
ret_ignored = pipe(pipe_fd); |
333 |
switch (fork()) { |
334 |
case 0: |
335 |
errno = 0; |
336 |
ptrace(PTRACE_TRACEME, 0, NULL, NULL); |
337 |
status = errno; |
338 |
ret_ignored = write(pipe_fd[1], &status, |
339 |
sizeof(status)); |
340 |
_exit(0); |
341 |
case -1: |
342 |
fprintf(stderr, "fork() failed.\n"); |
343 |
break; |
344 |
default: |
345 |
close(pipe_fd[1]); |
346 |
ret_ignored = read(pipe_fd[0], &status, sizeof(status)); |
347 |
wait(NULL); |
348 |
close(pipe_fd[0]); |
349 |
errno = status; |
350 |
show_result(status ? EOF : 0, 0); |
351 |
} |
352 |
} |
353 |
unset_capability(); |
354 |
} |
355 |
|
356 |
int main(int argc, char *argv[]) |
357 |
{ |
358 |
ccs_test_init(); |
359 |
stage_capability_test(); |
360 |
clear_status(); |
361 |
if (0) { /* To suppress "defined but not used" warnings. */ |
362 |
write_domain_policy("", 0); |
363 |
write_exception_policy("", 0); |
364 |
} |
365 |
return 0; |
366 |
} |