-----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

Reply via email to