1 /******************************************************************************/ 2 /* */ 3 /* Copyright (c) International Business Machines Corp., 2007, 2008 */ 4 /* */ 5 /* This program is free software; you can redistribute it and/or modify */ 6 /* it under the terms of the GNU General Public License as published by */ 7 /* the Free Software Foundation; either version 2 of the License, or */ 8 /* (at your option) any later version. */ 9 /* */ 10 /* This program is distributed in the hope that it will be useful, */ 11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 13 /* the GNU General Public License for more details. */ 14 /* */ 15 /* You should have received a copy of the GNU General Public License */ 16 /* along with this program; if not, write to the Free Software */ 17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18 /* */ 19 /******************************************************************************/ 20 /* 21 * File: verify_caps_exec.c 22 * Author: Serge Hallyn 23 * Purpose: perform several tests of file capabilities: 24 * 1. try setting caps without privilege 25 * 2. test proper calculation of pI', pE', and pP'. 26 * Try setting valid caps, drop rights, and run the executable, 27 * make sure we get the rights 28 */ 29 30 #include <stdio.h> 31 #include <unistd.h> 32 #include <endian.h> 33 #include <byteswap.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <sys/wait.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include "config.h" 40 #if HAVE_SYS_CAPABILITY_H 41 #include <linux/types.h> 42 #include <sys/capability.h> 43 #endif 44 #include <sys/prctl.h> 45 #include "test.h" 46 47 #define TSTPATH "print_caps" 48 char *TCID = "filecaps"; 49 int TST_TOTAL = 1; 50 51 int errno; 52 53 static void usage(const char *me) 54 { 55 tst_resm(TFAIL, "Usage: %s <0|1> [arg]\n", me); 56 tst_resm(TINFO, " 0: set file caps without privilege\n"); 57 tst_resm(TINFO, " 1: test that file caps are set correctly on exec\n"); 58 tst_exit(); 59 } 60 61 #define DROP_PERMS 0 62 #define KEEP_PERMS 1 63 64 #ifdef HAVE_LIBCAP 65 static void print_my_caps(void) 66 { 67 cap_t cap = cap_get_proc(); 68 char *txt = cap_to_text(cap, NULL); 69 tst_resm(TINFO, "\ncaps are %s\n", txt); 70 cap_free(cap); 71 cap_free(txt); 72 } 73 74 static void drop_root(int keep_perms) 75 { 76 int ret; 77 78 if (keep_perms) 79 prctl(PR_SET_KEEPCAPS, 1); 80 ret = setresuid(1000, 1000, 1000); 81 if (ret) { 82 tst_brkm(TFAIL | TERRNO, NULL, "Error dropping root privs\n"); 83 tst_exit(); 84 } 85 if (keep_perms) { 86 cap_t cap = cap_from_text("=eip"); 87 int ret; 88 if (!cap) 89 tst_brkm(TBROK | TERRNO, NULL, 90 "cap_from_text failed\n"); 91 ret = cap_set_proc(cap); 92 if (ret < 0) 93 tst_brkm(TBROK | TERRNO, NULL, "cap_set_proc failed\n"); 94 cap_free(cap); 95 } 96 } 97 98 static int perms_test(void) 99 { 100 int ret; 101 cap_t cap; 102 103 drop_root(DROP_PERMS); 104 cap = cap_from_text("all=eip"); 105 if (!cap) { 106 tst_resm(TFAIL, "could not get cap from text for perms test\n"); 107 return 1; 108 } 109 ret = cap_set_file(TSTPATH, cap); 110 if (ret) { 111 tst_resm(TPASS, "could not set capabilities as non-root\n"); 112 ret = 0; 113 } else { 114 tst_resm(TFAIL, "could set capabilities as non-root\n"); 115 ret = 1; 116 } 117 118 cap_free(cap); 119 return ret; 120 } 121 122 #define FIFOFILE "/tmp/caps_fifo" 123 static void create_fifo(void) 124 { 125 int ret; 126 127 ret = mkfifo(FIFOFILE, S_IRWXU | S_IRWXG | S_IRWXO); 128 if (ret == -1 && errno != EEXIST) 129 tst_brkm(TFAIL | TERRNO, NULL, "failed creating %s\n", 130 FIFOFILE); 131 } 132 133 static void write_to_fifo(const char *buf) 134 { 135 int fd; 136 137 fd = open(FIFOFILE, O_WRONLY); 138 write(fd, buf, strlen(buf)); 139 close(fd); 140 } 141 142 static void read_from_fifo(char *buf) 143 { 144 int fd; 145 146 memset(buf, 0, 200); 147 fd = open(FIFOFILE, O_RDONLY); 148 if (fd < 0) 149 tst_brkm(TFAIL | TERRNO, NULL, "Failed opening fifo\n"); 150 read(fd, buf, 199); 151 close(fd); 152 } 153 154 static int fork_drop_and_exec(int keepperms, cap_t expected_caps) 155 { 156 157 int pid; 158 int ret = 0; 159 char buf[200], *p; 160 char *capstxt; 161 cap_t actual_caps; 162 static int seqno; 163 164 pid = fork(); 165 if (pid < 0) 166 tst_brkm(TFAIL | TERRNO, NULL, "%s: failed fork\n", __func__); 167 if (pid == 0) { 168 drop_root(keepperms); 169 print_my_caps(); 170 sprintf(buf, "%d", seqno); 171 ret = execlp(TSTPATH, TSTPATH, buf, NULL); 172 capstxt = cap_to_text(expected_caps, NULL); 173 snprintf(buf, 200, "failed to run as %s\n", capstxt); 174 cap_free(capstxt); 175 write_to_fifo(buf); 176 tst_brkm(TFAIL, NULL, "%s: exec failed\n", __func__); 177 } else { 178 p = buf; 179 while (1) { 180 int c, s; 181 read_from_fifo(buf); 182 c = sscanf(buf, "%d", &s); 183 if (c == 1 && s == seqno) 184 break; 185 tst_resm(TINFO, 186 "got a bad seqno (c=%d, s=%d, seqno=%d)", c, s, 187 seqno); 188 } 189 p = index(buf, '.'); 190 if (!p) 191 tst_brkm(TFAIL, NULL, 192 "got a bad message from print_caps\n"); 193 p += 1; 194 actual_caps = cap_from_text(p); 195 if (cap_compare(actual_caps, expected_caps) != 0) { 196 capstxt = cap_to_text(expected_caps, NULL); 197 tst_resm(TINFO, 198 "Expected to run as .%s., ran as .%s..\n", 199 capstxt, p); 200 tst_resm(TINFO, "those are not the same\n"); 201 cap_free(capstxt); 202 ret = -1; 203 } 204 cap_free(actual_caps); 205 seqno++; 206 } 207 return ret; 208 } 209 210 static int caps_actually_set_test(void) 211 { 212 int whichcap, finalret = 0, ret; 213 cap_t fcap, pcap, cap_fullpi; 214 cap_value_t capvalue[1]; 215 int i; 216 217 fcap = cap_init(); 218 pcap = cap_init(); 219 if (!fcap || !pcap) { 220 perror("cap_init"); 221 exit(2); 222 } 223 224 create_fifo(); 225 226 int num_caps; 227 228 for (num_caps = 0;; num_caps++) { 229 ret = prctl(PR_CAPBSET_READ, num_caps); 230 /* 231 * Break from the loop in this manner to avoid incrementing, 232 * then having to decrement value. 233 */ 234 if (ret == -1) 235 break; 236 } 237 238 /* first, try each bit in fP (forced) with fE on and off. */ 239 for (whichcap = 0; whichcap < num_caps; whichcap++) { 240 /* 241 * fP=whichcap, fE=fI=0 242 * pP'=whichcap, pI'=pE'=0 243 */ 244 capvalue[0] = whichcap; 245 cap_clear(fcap); 246 cap_set_flag(fcap, CAP_PERMITTED, 1, capvalue, CAP_SET); 247 ret = cap_set_file(TSTPATH, fcap); 248 if (ret) { 249 tst_resm(TINFO, "%d\n", whichcap); 250 continue; 251 } 252 ret = fork_drop_and_exec(DROP_PERMS, fcap); 253 if (ret) { 254 tst_resm(TINFO, 255 "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=0\n", 256 whichcap); 257 if (!finalret) 258 finalret = ret; 259 } 260 261 /* SERGE here */ 262 /* 263 * fP = fE = whichcap, fI = 0 264 * pP = pE = whichcap, pI = 0 265 */ 266 cap_clear(fcap); 267 cap_set_flag(fcap, CAP_PERMITTED, 1, capvalue, CAP_SET); 268 cap_set_flag(fcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); 269 ret = cap_set_file(TSTPATH, fcap); 270 if (ret) { 271 tst_resm(TINFO, "%d\n", whichcap); 272 continue; 273 } 274 ret = fork_drop_and_exec(DROP_PERMS, fcap); 275 if (ret) { 276 tst_resm(TINFO, 277 "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=1\n", 278 whichcap); 279 if (!finalret) 280 finalret = ret; 281 } 282 } 283 284 cap_free(pcap); 285 cap_free(fcap); 286 cap_fullpi = cap_init(); 287 for (i = 0; i < num_caps; i++) { 288 capvalue[0] = i; 289 cap_set_flag(cap_fullpi, CAP_INHERITABLE, 1, capvalue, CAP_SET); 290 } 291 292 /* 293 * For the inheritable tests, we want to make sure pI starts 294 * filled. 295 */ 296 ret = cap_set_proc(cap_fullpi); 297 if (ret) 298 tst_resm(TINFO, "Could not fill pI. pI tests will fail.\n"); 299 300 /* 301 * next try each bit in fI 302 * The first two attemps have the bit which is in fI in pI. 303 * This should result in the bit being in pP'. 304 * If fE was set then it should also be in pE'. 305 * The last attempt starts with an empty pI. 306 * This should result in empty capability, as there were 307 * no bits to be inherited from the original process. 308 */ 309 for (whichcap = 0; whichcap < num_caps; whichcap++) { 310 cap_t cmpcap; 311 capvalue[0] = whichcap; 312 313 /* 314 * fI=whichcap, fP=fE=0 315 * pI=full 316 * pI'=full, pP'=whichcap, pE'=0 317 */ 318 /* fill pI' */ 319 pcap = cap_dup(cap_fullpi); 320 /* pP' = whichcap */ 321 cap_set_flag(pcap, CAP_PERMITTED, 1, capvalue, CAP_SET); 322 323 /* fI = whichcap */ 324 fcap = cap_init(); 325 cap_set_flag(fcap, CAP_INHERITABLE, 1, capvalue, CAP_SET); 326 ret = cap_set_file(TSTPATH, fcap); 327 if (ret) { 328 tst_resm(TINFO, "%d\n", whichcap); 329 continue; 330 } 331 ret = fork_drop_and_exec(KEEP_PERMS, pcap); 332 if (ret) { 333 tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d " 334 "CAP_EFFECTIVE=0\n", whichcap); 335 if (!finalret) 336 finalret = ret; 337 } 338 339 /* 340 * fI=fE=whichcap, fP=0 341 * pI=full 342 * pI'=full, pP'=whichcap, pE'=whichcap 343 * 344 * Note that only fE and pE' change, so keep prior 345 * fcap and pcap and set those bits. 346 */ 347 348 cap_set_flag(fcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); 349 cap_set_flag(pcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); 350 ret = cap_set_file(TSTPATH, fcap); 351 if (ret) { 352 tst_resm(TINFO, "%d\n", whichcap); 353 continue; 354 } 355 /* The actual result will be a full pI, with 356 * pE and pP containing just whichcap. */ 357 cmpcap = cap_dup(cap_fullpi); 358 cap_set_flag(cmpcap, CAP_PERMITTED, 1, capvalue, CAP_SET); 359 cap_set_flag(cmpcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); 360 ret = fork_drop_and_exec(KEEP_PERMS, cmpcap); 361 cap_free(cmpcap); 362 if (ret) { 363 tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d " 364 "CAP_EFFECTIVE=1\n", whichcap); 365 if (!finalret) 366 finalret = ret; 367 } 368 369 /* 370 * fI=fE=whichcap, fP=0 (so fcap is same as before) 371 * pI=0 (achieved using DROP_PERMS) 372 * pI'=pP'=pE'=0 373 */ 374 cap_clear(pcap); 375 ret = fork_drop_and_exec(DROP_PERMS, pcap); 376 if (ret) { 377 tst_resm(TINFO, 378 "Failed without_perms CAP_INHERITABLE=%d", 379 whichcap); 380 if (!finalret) 381 finalret = ret; 382 } 383 384 cap_free(fcap); 385 cap_free(pcap); 386 } 387 388 cap_free(cap_fullpi); 389 390 return finalret; 391 } 392 #endif 393 394 int main(int argc, char *argv[]) 395 { 396 #ifdef HAVE_LIBCAP 397 if (argc < 2) 398 usage(argv[0]); 399 400 int ret = 0; 401 402 switch (atoi(argv[1])) { 403 case 0: 404 ret = perms_test(); 405 break; 406 case 1: 407 ret = caps_actually_set_test(); 408 if (ret) 409 tst_resm(TFAIL, "Some tests failed\n"); 410 else 411 tst_resm(TPASS, "All tests passed\n"); 412 break; 413 default: 414 usage(argv[0]); 415 } 416 #else 417 tst_resm(TCONF, "System doesn't have POSIX capabilities support."); 418 #endif 419 420 tst_exit(); 421 } 422