Hi Andrew, The original verify_caps_exec.c test in the filecaps test was written before libcap had file capabilities support. Faced with implementing 64-bit support in that ugly mess in order to properly test your per-process securebits patch, it seemed wise to just switch to using libcap :) Does the following new version of the file look kosher to you?
thanks, -serge /******************************************************************************/ /* */ /* Copyright (c) International Business Machines Corp., 2007, 2008 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ /* the GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /* * File: verify_caps_exec.c * Author: Serge Hallyn * Purpose: perform several tests of file capabilities: * 1. try setting caps without CAP_SYS_ADMIN * 2. test proper calculation of pI', pE', and pP'. * Try setting valid caps, drop rights, and run the executable, * make sure we get the rights */ #define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <endian.h> #include <byteswap.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <errno.h> #include <fcntl.h> #include <sys/capability.h> #include <sys/prctl.h> #include <test.h> #define TSTPATH "./print_caps" char *TCID = "filecaps"; int TST_TOTAL=1; int errno; void usage(char *me) { tst_resm(TFAIL, "Usage: %s <0|1> [arg]\n", me); tst_resm(TINFO, " 0: set file caps without CAP_SYS_ADMIN\n"); tst_resm(TINFO, " 1: test that file caps are set correctly on exec\n"); tst_exit(1); } #define DROP_PERMS 0 #define KEEP_PERMS 1 void print_my_caps() { cap_t cap = cap_get_proc(); tst_resm(TINFO, "\ncaps are %s\n", cap_to_text(cap, NULL)); } int drop_root(int keep_perms) { int ret; if (keep_perms) prctl(PR_SET_KEEPCAPS, 1); ret = setresuid(1000, 1000, 1000); if (ret) { perror("setresuid"); tst_resm(TFAIL, "Error dropping root privs\n"); tst_exit(4); } if (keep_perms) { cap_t cap = cap_from_text("=eip"); cap_set_proc(cap); } return 1; } /* * TODO: find a better way to do this. Emulate libcap's * way, or just take it from linux/capability.h */ #ifndef __CAP_BITS #define __CAP_BITS 34 #endif int perms_test(void) { int ret; cap_t cap; drop_root(DROP_PERMS); cap = cap_from_text("all=eip"); if (!cap) { tst_resm(TFAIL, "could not get cap from text for perms test\n"); return 1; } ret = cap_set_file(TSTPATH, cap); if (ret) { tst_resm(TPASS, "could not set capabilities as non-root\n"); ret = 0; } else { tst_resm(TFAIL, "could set capabilities as non-root\n"); ret = 1; } cap_free(cap); return ret; } #define FIFOFILE "caps_fifo" void create_fifo(void) { int ret; ret = mkfifo(FIFOFILE, S_IRWXU | S_IRWXG | S_IRWXO); if (ret == -1 && errno != EEXIST) { perror("mkfifo"); tst_resm(TFAIL, "failed creating %s\n", FIFOFILE); tst_exit(1); } } void write_to_fifo(char *buf) { int fd; fd = open(FIFOFILE, O_WRONLY); write(fd, buf, strlen(buf)); close(fd); } void read_from_fifo(char *buf) { int fd; memset(buf, 0, 200); fd = open(FIFOFILE, O_RDONLY); if (fd < 0) { perror("open"); tst_resm(TFAIL, "Failed opening fifo\n"); tst_exit(1); } read(fd, buf, 199); close(fd); } int compare_caps(char *buf1, char *buf2) { int res; res = strcmp(buf1, buf2) == 0; return res; } int fork_drop_and_exec(int keepperms, char *capstxt) { int pid; int ret = 0; char buf[200], *p; static int seqno = 0; pid = fork(); if (pid < 0) { perror("fork"); tst_resm(TFAIL, "%s: failed fork\n", __FUNCTION__); tst_exit(1); } if (pid == 0) { drop_root(keepperms); print_my_caps(); sprintf(buf, "%d", seqno); ret = execlp(TSTPATH, TSTPATH, buf, NULL); perror("execl"); tst_resm(TFAIL, "%s: exec failed\n", __FUNCTION__); snprintf(buf, 200, "failed to run as %s\n", capstxt); write_to_fifo(buf); tst_exit(1); } else { p = buf; while (1) { int c, s; read_from_fifo(buf); c = sscanf(buf, "%d", &s); if (c==1 && s==seqno) break; tst_resm(TINFO, "got a bad seqno (c=%d, s=%d, seqno=%d)", c, s, seqno); } p = index(buf, '.')+1; if (p==(char *)1) { tst_resm(TFAIL, "got a bad message from print_caps\n"); tst_exit(1); } tst_resm(TINFO, "Expected to run as .%s., ran as .%s..\n", capstxt, p); if (strcmp(p, capstxt) != 0) { tst_resm(TINFO, "those are not the same\n"); ret = -1; } seqno++; } return ret; } int caps_actually_set_test(void) { int whichset, whichcap, finalret = 0, ret; cap_t cap, pcap; char *capstxt; cap_value_t capvalue[1]; cap = cap_init(); pcap = cap_init(); if (!cap || !pcap) { perror("cap_init"); exit(2); } create_fifo(); /* first, try each bit in fP (forced) with fE on and off. */ for (whichcap=0; whichcap < __CAP_BITS; whichcap++) { /* fE = 0, don't gain the perm */ capvalue[0] = whichcap; cap_clear(cap); cap_set_flag(cap, CAP_PERMITTED, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, cap); if (ret) { tst_resm(TINFO, "%d %d\n", whichset, whichcap); continue; } capstxt = cap_to_text(cap, NULL); ret = fork_drop_and_exec(DROP_PERMS, capstxt); if (ret) { tst_resm(TINFO, "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=0\n", whichcap); if (!finalret) finalret = ret; } /* SERGE here */ /* fE = 1, do gain the perm */ cap_clear(cap); cap_set_flag(cap, CAP_PERMITTED, 1, capvalue, CAP_SET); cap_set_flag(cap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, cap); if (ret) { tst_resm(TINFO, "%d %d\n", whichset, whichcap); continue; } capstxt = cap_to_text(cap, NULL); if (strcmp(capstxt, "=")==0) { tst_resm(TINFO, "%s: libcap doesn't know about cap %d, not running\n", __FUNCTION__, whichcap); ret = 0; } else ret = fork_drop_and_exec(DROP_PERMS, capstxt); if (ret) { tst_resm(TINFO, "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=1\n", whichcap); if (!finalret) finalret = ret; } } /* * next try each bit in fI * The first two attemps have the bit which is in fI in pI. * This should result in the bit being in pP'. * If fE was set then it should also be in pE'. * The last attempt starts with an empty pI. * This should result in empty capability, as there were * no bits to be inherited from the original process. */ for (whichcap=0; whichcap < __CAP_BITS; whichcap++) { int i; /* * bit is in fI and pI, so should be in pI'. * but fE=0, so cap is in pP' but not pE'. */ cap_clear(cap); cap_clear(pcap); for (i=0; i<__CAP_BITS; i++) { capvalue[0] = i; cap_set_flag(pcap, CAP_INHERITABLE, 1, capvalue, CAP_SET); } capvalue[0] = whichcap; cap_set_flag(cap, CAP_INHERITABLE, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, cap); if (ret) { tst_resm(TINFO, "%d %d\n", whichset, whichcap); continue; } cap_set_flag(pcap, CAP_PERMITTED, 1, capvalue, CAP_SET); capstxt = cap_to_text(pcap, NULL); ret = fork_drop_and_exec(KEEP_PERMS, capstxt); if (ret) { tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d " "CAP_EFFECTIVE=0\n", whichcap); if (!finalret) finalret = ret; } /* * bit is in fI and pI, so should be in pI'. * and fE=1, so cap is in pP' and pE'. */ cap_set_flag(cap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); ret = cap_set_file(TSTPATH, cap); if (ret) { tst_resm(TINFO, "%d %d\n", whichset, whichcap); continue; } cap_set_flag(pcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET); capstxt = cap_to_text(pcap, NULL); if (strcmp(capstxt, "=")==0) { tst_resm(TINFO, "%s: libcap doesn't know about cap %d, not running\n", __FUNCTION__, whichcap); ret = 0; } else ret = fork_drop_and_exec(KEEP_PERMS, capstxt); if (ret) { tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d " "CAP_EFFECTIVE=1\n", whichcap); if (!finalret) finalret = ret; } /* * bit is in fI but not in pI * So pP' is empty. * pE' must be empty. */ cap_clear(cap); capstxt = cap_to_text(cap, NULL); ret = fork_drop_and_exec(DROP_PERMS, capstxt); if (ret) { tst_resm(TINFO, "Failed without_perms CAP_INHERITABLE=%d", whichcap); if (!finalret) finalret = ret; } } cap_free(cap); return finalret; } int main(int argc, char *argv[]) { int ret = 0; if (argc < 2) usage(argv[0]); switch(atoi(argv[1])) { case 0: ret = perms_test(); break; case 1: ret = caps_actually_set_test(); if (ret) tst_resm(TFAIL, "Some tests failed\n"); else tst_resm(TPASS, "All tests passed\n"); break; default: usage(argv[0]); } tst_exit(ret); } ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Ltp-list mailing list Ltp-list@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ltp-list