On Mon, 2008-02-04 at 21:53 -0600, Serge E. Hallyn wrote: > 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?
Hi Andrew, Can you please provide your comments on this test case from Sergei? We are looking forward, and, would be happy to see this inside LTP post comments. Regards-- Subrata > > 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 ------------------------------------------------------------------------- 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