-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Subrata,
I have to apologize. I'm not very familiar with LTP tests and have been putting this off until I had time to figure all this out... I've still not figured out how to run this but, browsing over the source code, have noted a number of things. Please see my comments inline. PS. What should I read to get up to speed on LTP? Thanks Andrew Subrata Modak wrote: | Andrew, | | Your thoughts on this ;-) | | --Subrata | |> 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"); Not sure what is significant about CAP_SYS_ADMIN. |>> 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)); cap_free()? |>> } |>> |>> 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); cap_free()? |>> } |>> |>> 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 I guess you might be able to use PR_GET_SECUREBITS to tell you what the max supported capability of the running kernel is. |>> |>> 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; captext gets allocated in multiple places, but I can't see where it is cap_free()'d. |>> 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); Not clear where whichset is initialized. If TSTPATH refers to a file that it not present, then this test seems to pass. Is that intended? |>> 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 | -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.6 (GNU/Linux) iD8DBQFHwcJ/+bHCR3gb8jsRAo9fAKCF8va8NWVGr7od+sbejMnXnDKX/ACgt2+z RW6dx+q7UPgEVOidmcBJKAE= =Hxh7 -----END PGP SIGNATURE----- ------------------------------------------------------------------------- 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