Quoting Andrew G. Morgan ([EMAIL PROTECTED]):
> -----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.

Documentation error.  Note that the test drops all caps.

>
> |>>   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()?

Yup, to all instances of this comment.

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

Good idea.  Or if Kaigai's patch goes in that coudl be used...

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

Good point.  Though note that the cap_to_text manpage is confusing here
- do i free(capstxt), or do I cap_free(cap) as the manpage implies and
automatically free capstxt that way?  Reading the manpage on my system
kind of implies that so long as I cap_init at the start and
cap_free(cap) at the end, capstxt will be freed at the end...  Though
that's probably not right.

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

In the previous version :)

> If TSTPATH refers to a file that it not present, then this test seems to
> pass. Is that intended?

No, just an assumption of proper ltp setup.  Should fix that.

> |>>                   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);
> |>> }

Thanks Andrew, I'll try to get around to sending a new patch "soon".  In
the meantime, i would argue that applying the existing patch is better
than doing nothing since the previous version does not work with 64-bit
capabilities.  Is that ok with you?

thanks,
-serge

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