@@ -38,6 +38,10 @@ ifeq ($(shell grep -q netlink_iscsi_socket $(POLDEV)/include/support/all_perms.s
TARGETS += test_netlink_socket.te
endif
+ifeq ($(shell grep -q getrlimit $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS += test_prlimit.te
+endif
+
ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te, $(TARGETS))
endif
new file mode 100644
@@ -0,0 +1,52 @@
+########################################
+#
+# Policy for testing prlimit(2) permission checks.
+
+attribute prlimittestdomain;
+
+# prlimit_test(permission)
+# Generate a pair of test domains and rules for
+# testing the specified permission check.
+#
+define(`prlimit_test', `
+# Domain that is allowed $1 permission to the child.
+type test_$1_t;
+domain_type(test_$1_t)
+unconfined_runs_test(test_$1_t)
+typeattribute test_$1_t prlimittestdomain;
+typeattribute test_$1_t testdomain;
+
+# Child domain
+type test_$1_child_t;
+domain_type(test_$1_child_t)
+unconfined_runs_test(test_$1_child_t)
+typeattribute test_$1_child_t prlimittestdomain;
+typeattribute test_$1_child_t testdomain;
+
+# Transition from parent to child.
+spec_domtrans_pattern(test_$1_t, test_file_t, test_$1_child_t)
+
+# Allow parent $1 to child.
+allow test_$1_t test_$1_child_t:process $1;
+
+# Domain that is not allowed $1 permission.
+type test_no_$1_t;
+domain_type(test_no_$1_t)
+unconfined_runs_test(test_no_$1_t)
+typeattribute test_no_$1_t prlimittestdomain;
+typeattribute test_no_$1_t testdomain;
+
+# Transition from parent to child.
+spec_domtrans_pattern(test_no_$1_t, test_file_t, test_$1_child_t)
+')
+
+prlimit_test(setrlimit)
+prlimit_test(getrlimit)
+
+#
+# Common rules for all prlimit test domains.
+#
+
+# Entry into the test domains via the test program.
+miscfiles_domain_entry_test_files(prlimittestdomain)
+userdom_sysadm_entry_spec_domtrans_to(prlimittestdomain)
@@ -24,6 +24,10 @@ ifeq ($(shell grep -q netlink_iscsi_socket $(POLDEV)/include/support/all_perms.s
SUBDIRS += netlink_socket
endif
+ifeq ($(shell grep -q getrlimit $(POLDEV)/include/support/all_perms.spt && echo true),true)
+SUBDIRS += prlimit
+endif
+
ifeq ($(DISTRO),RHEL4)
SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp overlay unix_socket, $(SUBDIRS))
endif
new file mode 100644
@@ -0,0 +1,7 @@
+TARGETS=parent child
+
+LDLIBS += -lselinux
+
+all: $(TARGETS)
+clean:
+ rm -f $(TARGETS)
new file mode 100644
@@ -0,0 +1,22 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+ char buf[1];
+ int rc;
+
+ buf[0] = 0;
+ rc = write(1, buf, sizeof buf);
+ if (rc < 0) {
+ perror("write");
+ exit(-1);
+ }
+ rc = read(0, buf, sizeof buf);
+ if (rc < 0) {
+ perror("read");
+ exit(-1);
+ }
+ exit(0);
+}
new file mode 100644
@@ -0,0 +1,164 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+void usage(char *progname)
+{
+ fprintf(stderr,
+ "usage: %s [-g] [-s soft|hard] newdomain program\n",
+ progname);
+ exit(-1);
+}
+
+#define RESOURCE RLIMIT_NOFILE
+
+int main(int argc, char **argv)
+{
+ char buf[1];
+ int pid, rc, fd[2], fd2[2], opt;
+ security_context_t context_s;
+ context_t context;
+ struct rlimit newrlim, oldrlim, *newrlimp = NULL, *oldrlimp = NULL;
+ bool get = false, set = false, soft = false;
+
+ while ((opt = getopt(argc, argv, "gs:")) != -1) {
+ switch (opt) {
+ case 'g':
+ get = true;
+ break;
+ case 's':
+ set = true;
+ if (!strcasecmp(optarg, "soft"))
+ soft = true;
+ else if (!strcasecmp(optarg, "hard"))
+ soft = false;
+ else
+ usage(argv[0]);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (!get && !set) {
+ usage(argv[0]);
+ exit(-1);
+ }
+
+ if ((argc - optind) != 2) {
+ usage(argv[0]);
+ exit(-1);
+ }
+
+ rc = getcon(&context_s);
+ if (rc < 0) {
+ fprintf(stderr, "%s: unable to get my context\n", argv[0]);
+ exit(-1);
+
+ }
+
+ context = context_new(context_s);
+ if (!context) {
+ fprintf(stderr, "%s: unable to create context structure\n", argv[0]);
+ exit(-1);
+ }
+
+ if (context_type_set(context, argv[optind])) {
+ fprintf(stderr, "%s: unable to set new type\n", argv[0]);
+ exit(-1);
+ }
+
+ freecon(context_s);
+ context_s = context_str(context);
+ if (!context_s) {
+ fprintf(stderr, "%s: unable to obtain new context string\n", argv[0]);
+ exit(-1);
+ }
+
+ rc = setexeccon(context_s);
+ if (rc < 0) {
+ fprintf(stderr, "%s: unable to set exec context to %s\n", argv[0], context_s);
+ exit(-1);
+ }
+
+ rc = getrlimit(RESOURCE, &oldrlim);
+ if (rc < 0) {
+ perror("getrlimit");
+ exit(-1);
+ }
+
+ rc = pipe(fd);
+ if (rc < 0) {
+ perror("pipe");
+ exit(-1);
+ }
+
+ rc = pipe(fd2);
+ if (rc < 0) {
+ perror("pipe");
+ exit(-1);
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ exit(-1);
+ } else if (pid == 0) {
+ dup2(fd[0], 0);
+ dup2(fd2[1], 1);
+ execv(argv[optind + 1], argv + optind + 1);
+ buf[0] = -1;
+ write(1, buf, 1);
+ close(1);
+ perror(argv[optind + 1]);
+ exit(-1);
+ }
+
+ rc = read(fd2[0], buf, 1);
+ if (rc < 0) {
+ perror("read");
+ exit(-1);
+ }
+
+ if (get)
+ oldrlimp = &oldrlim;
+
+ if (set) {
+ newrlimp = &newrlim;
+ if (soft) {
+ newrlim.rlim_max = oldrlim.rlim_max;
+ if (newrlim.rlim_cur == RLIM_INFINITY)
+ newrlim.rlim_cur = 1024;
+ else
+ newrlim.rlim_cur = oldrlim.rlim_cur / 2;
+ } else {
+ newrlim.rlim_cur = oldrlim.rlim_cur;
+ if (newrlim.rlim_max == RLIM_INFINITY)
+ newrlim.rlim_max = 1024;
+ else
+ newrlim.rlim_max = oldrlim.rlim_max / 2;
+ }
+ }
+
+ rc = prlimit(pid, RESOURCE, newrlimp, oldrlimp);
+ if (rc < 0) {
+ perror("prlimit");
+ write(fd[1], buf, 1);
+ close(fd[1]);
+ exit(1);
+ }
+
+ write(fd[1], buf, 1);
+ close(fd[1]);
+ exit(0);
+}
new file mode 100755
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+use Test;
+BEGIN { plan tests => 6}
+
+$basedir = $0; $basedir =~ s|(.*)/[^/]*|$1|;
+
+# Verify that test_setrlimit_t can set soft limit of test_setrlimit_child_t
+$result = system ("runcon -t test_setrlimit_t $basedir/parent -s soft test_setrlimit_child_t $basedir/child 2>&1");
+ok($result, 0); # we expect this to succeed.
+
+# Verify that test_no_setrlimit_t cannot set soft limit of test_setrlimit_child_t
+$result = system ("runcon -t test_no_setrlimit_t $basedir/parent -s soft test_setrlimit_child_t $basedir/child 2>&1");
+ok($result); # we expect this to fail.
+
+# Verify that test_setrlimit_t can set hard limit of test_setrlimit_child_t
+$result = system ("runcon -t test_setrlimit_t $basedir/parent -s hard test_setrlimit_child_t $basedir/child 2>&1");
+ok($result, 0); # we expect this to succeed.
+
+# Verify that test_no_setrlimit_t cannot set hard limit of test_setrlimit_child_t
+$result = system ("runcon -t test_no_setrlimit_t $basedir/parent -s hard test_setrlimit_child_t $basedir/child 2>&1");
+ok($result); # we expect this to fail.
+
+# Verify that test_getrlimit_t can get limits of test_setrlimit_child_t
+$result = system ("runcon -t test_getrlimit_t $basedir/parent -g test_getrlimit_child_t $basedir/child 2>&1");
+ok($result, 0); # we expect this to succeed.
+
+# Verify that test_no_getrlimit_t cannot get limit of test_setrlimit_child_t
+$result = system ("runcon -t test_no_getrlimit_t $basedir/parent -g test_getrlimit_child_t $basedir/child 2>&1");
+ok($result); # we expect this to fail.
Add tests for prlimit(2) permission checks for getting and setting resource limits of other processes. The tests are only executed if the new getrlimit permission is defined by the base policy. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> --- policy/Makefile | 4 ++ policy/test_prlimit.te | 52 ++++++++++++++++ tests/Makefile | 4 ++ tests/prlimit/Makefile | 7 +++ tests/prlimit/child.c | 22 +++++++ tests/prlimit/parent.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/prlimit/test | 30 +++++++++ 7 files changed, 283 insertions(+) create mode 100644 policy/test_prlimit.te create mode 100644 tests/prlimit/Makefile create mode 100644 tests/prlimit/child.c create mode 100644 tests/prlimit/parent.c create mode 100755 tests/prlimit/test