-----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
|>> [email protected]
|>> 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
|> [email protected]
|> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list