Just fyi, here are the ltp tests I try to use to test file capabilities.
It's a patch against the 20070430 ltp release, though it won't actually
be hooked in until i write a reliable little test for whether fscaps
are in the kernel and supported by userspace so compilation and testing
don't erroneously fail.
So for now to use this
cd ltp/testcases/kernel/security/filecaps
make noltp_check
thanks,
-serge
diff -Nrup ltp-full-20070430/runltp ltp-full-20070430-filecaps/runltp
--- ltp-full-20070430/runltp 2007-04-26 13:02:48.000000000 +0200
+++ ltp-full-20070430-filecaps/runltp 2007-05-23 00:32:02.000000000 +0200
@@ -284,7 +284,8 @@ main()
${LTPROOT}/runtest/mm ${LTPROOT}/runtest/ipc \
${LTPROOT}/runtest/sched ${LTPROOT}/runtest/math \
${LTPROOT}/runtest/nptl ${LTPROOT}/runtest/pty \
- ${LTPROOT}/runtest/containers
+ ${LTPROOT}/runtest/containers \
+ ${LTPROOT}/runtest/filecaps
do
[ -a "$SCENFILES" ] || \
{
diff -Nrup ltp-full-20070430/runtest/filecaps
ltp-full-20070430-filecaps/runtest/filecaps
--- ltp-full-20070430/runtest/filecaps 1970-01-01 01:00:00.000000000 +0100
+++ ltp-full-20070430-filecaps/runtest/filecaps 2007-05-23 00:04:33.000000000
+0200
@@ -0,0 +1,2 @@
+#DESCRIPTION:file capabilities
+Filecaps filecapstest.sh
diff -Nrup ltp-full-20070430/testcases/kernel/security/filecaps/Makefile
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/Makefile
--- ltp-full-20070430/testcases/kernel/security/filecaps/Makefile
1970-01-01 01:00:00.000000000 +0100
+++ ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/Makefile
2007-11-17 03:47:34.000000000 +0100
@@ -0,0 +1,33 @@
+CC=gcc
+
+CFLAGS += -I../../../../include -Wall
+LDLIBS += -L../../../../lib -lltp -lcap
+
+SRCS = $(wildcard *.c)
+TARGETS = $(patsubst %.c,%,$(SRCS))
+NOLTP_TARGETS = $(patsubst %.c,%_noltp,$(SRCS))
+SIGTARGETS = fcap_executable suid_executable fcapsuid_executable
+NOLTP_SIGTARGETS = fcap_executable_noltp suid_executable_noltp
fcapsuid_executable_noltp
+
+%_noltp : %.c
+ $(CC) -g -DNO_LTP -o $@ $< -lcap
+ cp plain_executable_noltp fcap_executable_noltp
+ setfcaps -c cap_sys_admin=p -e fcap_executable_noltp
+ cp plain_executable_noltp suid_executable_noltp
+ chmod u+s suid_executable_noltp
+ cp plain_executable_noltp fcapsuid_executable_noltp
+ chmod u+s fcapsuid_executable_noltp
+ setfcaps -c cap_sys_admin=p -e fcap_executable_noltp
+
+all: $(TARGETS) $(SIGTARGETS)
+
+noltp: $(NOLTP_TARGETS) $(NOLTP_SIGTARGETS)
+
+clean:
+ rm -f $(TARGETS) *.o $(NOLTP_TARGETS) caps_fifo $(SIGTARGETS)
$(NOLTP_SIGTARGETS)
+
+install:
+ @set -e; for i in $(TARGETS) $(SIGTARGETS) filecapstest.sh; do ln -f
$$i ../../../bin/$$i ; chmod +x ../../../bin/$$i; done
+
+noltp_check: noltp
+ ./runtests_noltp.sh
diff -Nrup ltp-full-20070430/testcases/kernel/security/filecaps/filecapstest.sh
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/filecapstest.sh
--- ltp-full-20070430/testcases/kernel/security/filecaps/filecapstest.sh
1970-01-01 01:00:00.000000000 +0100
+++
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/filecapstest.sh
2007-11-17 03:50:57.000000000 +0100
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+echo "Running in:"
+cp $LTPROOT/testcases/bin/print_caps .
+mkfifo caps_fifo
+chmod 777 caps_fifo
+exit_code=0
+echo "cap_sys_admin tests"
+testfilecaps 0
+tmp=$?
+if [ $tmp -ne 0 ]; then
+ exit_code=$tmp
+fi
+echo "testing for correct caps"
+testfilecaps 1
+tmp=$?
+if [ $tmp -ne 0 ]; then
+ exit_code=$tmp
+fi
+
+for i in `seq 1 10`; do
+ ./signals_noltp $i
+ tmp=$?
+ if [ $tmp -ne 0 ]; then
+ exit_code=$tmp;
+ fi
+done
+
+exit $exit_code
diff -Nrup
ltp-full-20070430/testcases/kernel/security/filecaps/plain_executable.c
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/plain_executable.c
--- ltp-full-20070430/testcases/kernel/security/filecaps/plain_executable.c
1970-01-01 01:00:00.000000000 +0100
+++
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/plain_executable.c
2007-11-17 00:24:15.000000000 +0100
@@ -0,0 +1,44 @@
+#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 <attr/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+
+#ifdef NO_LTP
+#define TFAIL "FAILURE: "
+#define TPASS "PASS: "
+#define TINFO "INFO: "
+#define tst_resm(x, format, arg...) printf("%s:" format, x, ## arg)
+#define tst_exit(x) exit(x)
+#define TSTPATH "./print_caps_noltp"
+#else
+#define TSTPATH "./print_caps"
+#include <test.h>
+char *TCID = "filecaps";
+int TST_TOTAL=1;
+#endif
+
+#define GOT_SIGNAL 1
+#define NO_SIGNAL 2
+
+void sighandler(int sig)
+{
+ exit(GOT_SIGNAL);
+}
+
+int main(int argc, char *argv[])
+{
+ signal(SIGUSR1, sighandler);
+ signal(SIGCONT, sighandler);
+ sleep(5);
+ exit(NO_SIGNAL);
+}
diff -Nrup ltp-full-20070430/testcases/kernel/security/filecaps/print_caps.c
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/print_caps.c
--- ltp-full-20070430/testcases/kernel/security/filecaps/print_caps.c
1970-01-01 01:00:00.000000000 +0100
+++ ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/print_caps.c
2007-10-15 23:58:40.000000000 +0200
@@ -0,0 +1,50 @@
+/*
+ * File: print_caps.c
+ * Author: Serge Hallyn
+ * Copyright 2007 IBM Corp
+ * Purpose: print out the POSIX capabilities with which it runs
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define FIFOFILE "caps_fifo"
+//#define DEBUG 1
+
+int main(int argc, char *argv[])
+{
+ cap_t cap = cap_get_proc();
+ int fd;
+ int seqno = 0;
+ char buf[2000];
+
+ if (argc>1)
+ seqno = atoi(argv[1]);
+
+ if (!cap) {
+ perror("print_caps - cap_get_proc");
+ exit(1);
+ }
+
+ fd = open(FIFOFILE, O_WRONLY);
+ if (!fd) {
+ perror("print_caps: open fifo");
+ exit(2);
+ }
+
+ snprintf(buf, 2000, "%d.%s", seqno, cap_to_text(cap, NULL));
+ write(fd, buf, strlen(buf)+1);
+ close(fd);
+#ifdef DEBUG
+ printf("%s: running with caps %s\n", argv[0], cap_to_text(cap, NULL));
+#endif
+
+ cap_free(cap);
+
+ return 0;
+}
diff -Nrup
ltp-full-20070430/testcases/kernel/security/filecaps/runtests_noltp.sh
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/runtests_noltp.sh
--- ltp-full-20070430/testcases/kernel/security/filecaps/runtests_noltp.sh
1970-01-01 01:00:00.000000000 +0100
+++
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/runtests_noltp.sh
2007-11-17 00:17:10.000000000 +0100
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+mkfifo caps_fifo
+chmod 777 caps_fifo
+exit_code=0
+echo "cap_sys_admin tests"
+./testfilecaps_noltp 0
+tmp=$?
+if [ $tmp -ne 0 ]; then
+ exit_code=$tmp
+fi
+echo "testing for correct caps"
+./testfilecaps_noltp 1
+tmp=$?
+if [ $tmp -ne 0 ]; then
+ exit_code=$tmp
+fi
+
+rm caps_fifo
+
+for i in `seq 1 10`; do
+ ./signals_noltp $i
+ tmp=$?
+ if [ $tmp -ne 0 ]; then
+ exit_code=$tmp;
+ fi
+done
+
+exit $exit_code
diff -Nrup ltp-full-20070430/testcases/kernel/security/filecaps/signals.c
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/signals.c
--- ltp-full-20070430/testcases/kernel/security/filecaps/signals.c
1970-01-01 01:00:00.000000000 +0100
+++ ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/signals.c
2007-11-17 00:33:06.000000000 +0100
@@ -0,0 +1,408 @@
+/*
+ * File: signals.c
+ * Author: Serge Hallyn
+ * Copyright 2007 IBM Corp
+ * Purpose: test signal sending authorization for file capabilities
+ */
+
+/*
+ * Tests:
+ * 1. chown(500); fork; P1:exec; P2:send SIGUSR1 to P1
+ * should succeed
+ * 2. chown(500); fork; P1: exec with filecaps; P2: send SIGUSR1 to P1
+ * should fail
+ * 3. chown(500); fork; P1: exec with filecaps; P2: send SIGCONT to P1
+ * should succeed
+ * 4. chown(500); fork; P1: setsid(); exec with filecaps;
+ * P2: send SIGCONT to P1
+ * should fail
+ * 5. chown(500); fork; P1: exec setuid(0) program; P2: send SIGUSR1 to P1
+ * should fail
+ * 6. chown(500); fork; P1: exec setuid(0) program; P2: send SIGCONT to P1
+ * should succeed
+ * 7. chown(500); fork; P1: exec setuid(501)+filecap program;
+ * P2: send SIGUSR1 to P1
+ * should fail
+ * 8. chown(500); fork; P1: exec setuid(501)+filecap program;
+ * P2: send SIGCONT to P1
+ * should succeed
+ * 9. chown(500); fork; P1: setsid(); exec setuid(501)+filecap program;
+ * P2: send SIGUSR1 to P1
+ * should fail
+ * 10. chown(500); fork; P1: setsid(); exec setuid(501)+filecap program;
+ * P2: send SIGCONT to P1
+ * should fail
+ */
+
+#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 <attr/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+
+#ifdef NO_LTP
+#define FNAM_PLAINFILE "./plain_executable_noltp"
+#define FNAM_FCAPFILE "./fcap_executable_noltp"
+#define FNAM_SUIDFILE "./suid_executable_noltp"
+#define FNAM_FCAPSUIDFILE "./fcapsuid_executable_noltp"
+#define TFAIL "FAILURE: "
+#define TPASS "PASS: "
+#define TINFO "INFO: "
+#define tst_resm(x, format, arg...) printf("%s:" format, x, ## arg)
+#define tst_exit(x) exit(x)
+#else
+#define FNAM_PLAINFILE "./plain_executable"
+#define FNAM_FCAPFILE "./fcap_executable"
+#define FNAM_SUIDFILE "./suid_executable"
+#define FNAM_FCAPSUIDFILE "./fcapsuid_executable"
+#include <test.h>
+char *TCID = "filecaps";
+int TST_TOTAL=1;
+#endif
+
+int errno;
+
+void usage(char *me)
+{
+ tst_resm(TFAIL, "Usage: %s <test_num>\n", me);
+ tst_resm(TFAIL, " test_num is between 1 and 10 inclusive\n");
+ tst_exit(1);
+}
+
+#define GOT_SIGNAL 1
+#define NO_SIGNAL 2
+
+int P1(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ execl(FNAM_PLAINFILE, FNAM_PLAINFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGUSR1);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TPASS, "test 1 got signal\n");
+ tst_exit(0);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TFAIL, "test 1 no signal\n");
+ tst_exit(1);
+ } else {
+ tst_resm(TFAIL, "test 1 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P2(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ execl(FNAM_FCAPFILE, FNAM_FCAPFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGUSR1);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TFAIL, "test 2 got signal\n");
+ tst_exit(1);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TPASS, "test 2 no signal\n");
+ tst_exit(0);
+ } else {
+ tst_resm(TFAIL, "test 2 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P3(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ execl(FNAM_FCAPFILE, FNAM_FCAPFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGCONT);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TPASS, "test 3 got signal\n");
+ tst_exit(0);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TFAIL, "test 3 no signal\n");
+ tst_exit(1);
+ } else {
+ tst_resm(TFAIL, "test 3 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P4(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ setsid();
+ execl(FNAM_FCAPFILE, FNAM_FCAPFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGCONT);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TFAIL, "test 4 got signal\n");
+ tst_exit(1);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TPASS, "test 4 no signal\n");
+ tst_exit(0);
+ } else {
+ tst_resm(TFAIL, "test 4 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P5(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ execl(FNAM_SUIDFILE, FNAM_SUIDFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGUSR1);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TFAIL, "test 5 got signal\n");
+ tst_exit(1);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TPASS, "test 5 no signal\n");
+ tst_exit(0);
+ } else {
+ tst_resm(TFAIL, "test 5 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P6(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ execl(FNAM_SUIDFILE, FNAM_SUIDFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGCONT);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TPASS, "test 6 got signal\n");
+ tst_exit(0);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TFAIL, "test 6 no signal\n");
+ tst_exit(1);
+ } else {
+ tst_resm(TFAIL, "test 6 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P7(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ execl(FNAM_FCAPSUIDFILE, FNAM_FCAPSUIDFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGUSR1);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TFAIL, "test 7 got signal\n");
+ tst_exit(1);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TPASS, "test 7 no signal\n");
+ tst_exit(0);
+ } else {
+ tst_resm(TFAIL, "test 7 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P8(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ execl(FNAM_FCAPSUIDFILE, FNAM_FCAPSUIDFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGCONT);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TPASS, "test 8 got signal\n");
+ tst_exit(0);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TFAIL, "test 8 no signal\n");
+ tst_exit(1);
+ } else {
+ tst_resm(TFAIL, "test 8 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P9(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ setsid();
+ execl(FNAM_FCAPSUIDFILE, FNAM_FCAPSUIDFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGUSR1);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TFAIL, "test 9 got signal\n");
+ tst_exit(1);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TPASS, "test 9 no signal\n");
+ tst_exit(0);
+ } else {
+ tst_resm(TFAIL, "test 9 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int P10(void)
+{
+ int status;
+ int pid = fork();
+
+ if (pid < 0) {
+ tst_resm(TFAIL, "failed to fork\n");
+ tst_exit(1);
+ }
+ if (pid == 0) {
+ setsid();
+ execl(FNAM_FCAPSUIDFILE, FNAM_FCAPSUIDFILE, NULL);
+ tst_resm(TFAIL, "failed to exec\n");
+ tst_exit(1);
+ }
+ sleep(1);
+ kill(pid, SIGCONT);
+ waitpid(pid, &status, 0);
+ status = WEXITSTATUS(status);
+ if (status == GOT_SIGNAL) {
+ tst_resm(TFAIL, "test 10 got signal\n");
+ tst_exit(1);
+ } else if (status == NO_SIGNAL) {
+ tst_resm(TPASS, "test 10 no signal\n");
+ tst_exit(0);
+ } else {
+ tst_resm(TFAIL, "test 10 got bogus result(%d)\n", status);
+ tst_exit(1);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int tstnum;
+
+ setuid(500);
+ if (argc < 2)
+ usage(argv[0]);
+ tstnum = atoi(argv[1]);
+ switch(tstnum) {
+ case 1: P1();
+ case 2: P2();
+ case 3: P3();
+ case 4: P4();
+ case 5: P5();
+ case 6: P6();
+ case 7: P7();
+ case 8: P8();
+ case 9: P9();
+ case 10: P10();
+ default: usage(argv[0]);
+ }
+}
diff -Nrup ltp-full-20070430/testcases/kernel/security/filecaps/testfilecaps.c
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/testfilecaps.c
--- ltp-full-20070430/testcases/kernel/security/filecaps/testfilecaps.c
1970-01-01 01:00:00.000000000 +0100
+++
ltp-full-20070430-filecaps/testcases/kernel/security/filecaps/testfilecaps.c
2007-11-05 23:14:22.000000000 +0100
@@ -0,0 +1,423 @@
+/*
+ * File: testfscaps.c
+ * Author: Serge Hallyn
+ * Copyright 2007 IBM Corp
+ * Purpose: perform several tests of file capabilities:
+ * 1. try setting caps without CAP_SYS_ADMIN
+ * 2. 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 <attr/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+
+#ifdef NO_LTP
+#define TFAIL "FAILURE: "
+#define TPASS "PASS: "
+#define TINFO "INFO: "
+#define tst_resm(x, format, arg...) printf("%s:" format, x, ## arg)
+#define tst_exit(x) exit(x)
+#define TSTPATH "./print_caps_noltp"
+#else
+#define TSTPATH "./print_caps"
+#include <test.h>
+char *TCID = "filecaps";
+int TST_TOTAL=1;
+#endif
+
+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_setpcap-eip");
+ cap_set_proc(cap);
+ }
+
+ return 1;
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define cpu_to_le32(x) x
+#else
+#define cpu_to_le32(x) bswap_32(x)
+#endif
+
+#define CAPNAME "security.capability"
+#ifndef __CAP_BITS
+#define __CAP_BITS 31
+#endif
+
+#define XATTR_CAPS_SZ (3*sizeof(__le32))
+#define VFS_CAP_REVISION_MASK 0xFF000000
+#define VFS_CAP_REVISION 0x01000000
+
+#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
+#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
+
+int perms_test(void)
+{
+ int ret;
+ unsigned int value[3];
+ unsigned int v;
+
+ drop_root(DROP_PERMS);
+ v = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+ value[0] = cpu_to_le32(v);
+ value[1] = 1;
+ value[2] = 1;
+ ret = setxattr(TSTPATH, CAPNAME, value, 3*sizeof(unsigned int), 0);
+ if (ret) {
+ perror("setxattr");
+ 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;
+ }
+
+ 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;
+
+ //printf("execing with %s\n", capstxt);
+ 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;
+ printf("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 i, whichset, whichcap, finalret = 0, ret;
+ cap_t cap;
+ char *capstxt;
+ unsigned int value[3];
+ cap_value_t capvalue[1];
+ unsigned int magic;
+
+ magic = VFS_CAP_REVISION;
+
+ cap = cap_init();
+ if (!cap) {
+ perror("cap_init");
+ exit(2);
+ }
+
+ create_fifo();
+
+ /* first, try each bit in fP (forced) with fE on and off. */
+ value[1] = value[2] = cpu_to_le32(0);
+ for (whichcap=0; whichcap < __CAP_BITS; whichcap++) {
+ if (whichcap == 8)
+ continue;
+ /* fE = 0, don't gain the perm */
+ capvalue[0] = whichcap;
+ value[0] = cpu_to_le32(magic);
+ value[1] = cpu_to_le32(1 << whichcap);
+ ret = setxattr(TSTPATH, CAPNAME, value, 3*sizeof(unsigned int),
0);
+ if (ret) {
+ tst_resm(TINFO, "%d %d\n", whichset, whichcap);
+ perror("setxattr");
+ continue;
+ }
+ /* do a sanity check */
+ cap_clear(cap);
+ cap_set_flag(cap, CAP_PERMITTED, 1, capvalue, CAP_SET);
+ 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;
+ }
+
+ /* fE = 1, do gain the perm */
+ value[0] = cpu_to_le32(magic | VFS_CAP_FLAGS_EFFECTIVE);
+ value[1] = cpu_to_le32(1 << whichcap);
+ ret = setxattr(TSTPATH, CAPNAME, value, 3*sizeof(unsigned int),
0);
+ if (ret) {
+ tst_resm(TINFO, "%d %d\n", whichset, whichcap);
+ perror("setxattr");
+ continue;
+ }
+ /* do a sanity check */
+ cap_clear(cap);
+ cap_set_flag(cap, CAP_PERMITTED, 1, capvalue, CAP_SET);
+ cap_set_flag(cap, CAP_EFFECTIVE, 1, capvalue, CAP_SET);
+ 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.
+ */
+ value[1] = value[2] = cpu_to_le32(0);
+ for (whichcap=0; whichcap < __CAP_BITS; whichcap++) {
+ if (whichcap == 8)
+ continue;
+ /*
+ * bit is in fI and pI, so should be in pI'.
+ * but fE=0, so cap is in pP' but not pE'.
+ */
+ value[0] = cpu_to_le32(magic);
+ value[2] = cpu_to_le32(1 << whichcap);
+ ret = setxattr(TSTPATH, CAPNAME, value, 3*sizeof(unsigned int),
0);
+ if (ret) {
+ tst_resm(TINFO, "%d %d\n", whichset, whichcap);
+ perror("setxattr");
+ continue;
+ }
+ /* do a sanity check */
+ cap_clear(cap);
+ for (i=0; i<32; i++) {
+ if (i != 8) {
+ capvalue[0] = i;
+ cap_set_flag(cap, CAP_INHERITABLE, 1, capvalue,
CAP_SET);
+ }
+ }
+ capvalue[0] = whichcap;
+ cap_set_flag(cap, CAP_PERMITTED, 1, capvalue, CAP_SET);
+ capstxt = cap_to_text(cap, 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'.
+ */
+
+ value[0] = cpu_to_le32(magic | VFS_CAP_FLAGS_EFFECTIVE);
+ value[2] = cpu_to_le32(1 << whichcap);
+ ret = setxattr(TSTPATH, CAPNAME, value, 3*sizeof(unsigned int),
0);
+ if (ret) {
+ tst_resm(TINFO, "%d %d\n", whichset, whichcap);
+ perror("setxattr");
+ continue;
+ }
+ /* do a sanity check */
+ cap_clear(cap);
+ for (i=0; i<32; i++) {
+ if (i != 8) {
+ capvalue[0] = i;
+ cap_set_flag(cap, CAP_INHERITABLE, 1, capvalue,
CAP_SET);
+ }
+ }
+ capvalue[0] = whichcap;
+ cap_set_flag(cap, CAP_PERMITTED, 1, capvalue, CAP_SET);
+ cap_set_flag(cap, CAP_EFFECTIVE, 1, capvalue, CAP_SET);
+ 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(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.
+ */
+ value[0] = cpu_to_le32(magic | VFS_CAP_FLAGS_EFFECTIVE);
+ value[2] = cpu_to_le32(1 << whichcap);
+ ret = setxattr(TSTPATH, CAPNAME, value, 3*sizeof(unsigned int),
0);
+ if (ret) {
+ tst_resm(TINFO, "%d %d\n", whichset, whichcap);
+ perror("setxattr");
+ continue;
+ }
+ /* do a sanity check */
+ 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);
+}
diff -Nrup ltp-full-20070430/testscripts/test_filecaps.sh
ltp-full-20070430-filecaps/testscripts/test_filecaps.sh
--- ltp-full-20070430/testscripts/test_filecaps.sh 1970-01-01
01:00:00.000000000 +0100
+++ ltp-full-20070430-filecaps/testscripts/test_filecaps.sh 2007-05-23
00:00:10.000000000 +0200
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# Copyright 2007 IBM
+#
+# 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.
+#
+# test_filecaps.sh - Run the file capabilities test suite.
+
+# Must be root to run the containers testsuite
+if [ $UID != 0 ]
+then
+ echo "FAILED: Must be root to execute this script"
+ exit 1
+fi
+
+# set the LTPROOT directory
+cd `dirname $0`
+LTPROOT=${PWD}
+echo $LTPROOT | grep testscripts > /dev/null 2>&1
+if [ $? -eq 0 ]
+then
+ cd ..
+ LTPROOT=${PWD}
+fi
+
+# set the PATH to include testcase/bin
+
+export PATH=$PATH:/usr/sbin:$LTPROOT/testcases/bin
+export LTPBIN=$LTPROOT/testcases/bin
+
+# We will store the logfiles in $LTPROOT/results, so make sure
+# it exists.
+if [ ! -d $LTPROOT/results ]
+then
+ mkdir $LTPROOT/results
+fi
+
+# Check the role and mode testsuite is being executed under.
+echo "Running the file capabilities testsuite..."
+
+$LTPROOT/pan/pan -S -a $LTPROOT/results/filecaps -n ltp-filecaps -l
$LTPROOT/results/filecaps.logfile -o $LTPROOT/results/filecaps.outfile -p -f
$LTPROOT/runtest/filecaps
+
+echo "Done."
+exit 0
-
To unsubscribe from this list: send the line "unsubscribe
linux-security-module" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html