All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Smalley <stephen.smalley.work@gmail.com>
To: paul@paul-moore.com
Cc: selinux@vger.kernel.org, Stephen Smalley <sds@tycho.nsa.gov>
Subject: [RFC PATCH] libsepol,secilc,policycoreutils: add unprivileged sandboxing capability
Date: Fri, 13 Mar 2020 09:41:50 -0400	[thread overview]
Message-ID: <20200313134150.27492-1-stephen.smalley.work@gmail.com> (raw)

From: Stephen Smalley <sds@tycho.nsa.gov>

This patch provides support in the selinux userspace for the
unprivileged sandboxing capability introduced by the previous kernel
patch.  As with that patch, this is a RFC on an early prototype of a
new capability to support unprivileged sandboxing.  See the kernel
patch description for a fuller description of the background, goals,
and approach.

This patch adds libsepol support for sandbox policies including deny
statements and it adds a secilc option for compiling a cil policy into
a binary sandbox file. It also adds a new utility called sebox that
allows a user to load and unload sandbox policies to the kernel.

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
---
 libsepol/cil/include/cil/cil.h             |   1 +
 libsepol/cil/src/cil.c                     |  10 ++
 libsepol/cil/src/cil_binary.c              |   3 +
 libsepol/cil/src/cil_build_ast.c           |   9 +
 libsepol/cil/src/cil_internal.h            |   7 +-
 libsepol/cil/src/cil_tree.c                |   3 +
 libsepol/include/sepol/policydb.h          |  11 ++
 libsepol/include/sepol/policydb/avtab.h    |   4 +-
 libsepol/include/sepol/policydb/policydb.h |   8 +-
 libsepol/src/libsepol.map.in               |   1 +
 libsepol/src/policydb_public.c             |   6 +
 libsepol/src/write.c                       |  95 ++++++++++
 policycoreutils/.gitignore                 |   1 +
 policycoreutils/Makefile                   |   2 +-
 policycoreutils/sebox/Makefile             |  28 +++
 policycoreutils/sebox/sebox.8              |  50 ++++++
 policycoreutils/sebox/sebox.c              | 200 +++++++++++++++++++++
 secilc/secilc.c                            |  33 +++-
 18 files changed, 467 insertions(+), 5 deletions(-)
 create mode 100644 policycoreutils/sebox/Makefile
 create mode 100644 policycoreutils/sebox/sebox.8
 create mode 100644 policycoreutils/sebox/sebox.c

diff --git a/libsepol/cil/include/cil/cil.h b/libsepol/cil/include/cil/cil.h
index f8cfc3be..d75d7401 100644
--- a/libsepol/cil/include/cil/cil.h
+++ b/libsepol/cil/include/cil/cil.h
@@ -59,6 +59,7 @@ extern void cil_set_attrs_expand_generated(struct cil_db *db, int attrs_expand_g
 extern void cil_set_attrs_expand_size(struct cil_db *db, unsigned attrs_expand_size);
 extern void cil_set_target_platform(cil_db_t *db, int target_platform);
 extern void cil_set_policy_version(cil_db_t *db, int policy_version);
+extern void cil_set_sandbox(cil_db_t *db, int sandbox);
 extern void cil_write_policy_conf(FILE *out, struct cil_db *db);
 
 enum cil_log_level {
diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
index c010ca2a..353d6413 100644
--- a/libsepol/cil/src/cil.c
+++ b/libsepol/cil/src/cil.c
@@ -238,6 +238,7 @@ char *CIL_KEY_UNORDERED;
 char *CIL_KEY_SRC_INFO;
 char *CIL_KEY_SRC_CIL;
 char *CIL_KEY_SRC_HLL;
+char *CIL_KEY_SANDBOXDENY;
 
 static void cil_init_keys(void)
 {
@@ -403,6 +404,7 @@ static void cil_init_keys(void)
 	CIL_KEY_SRC_INFO = cil_strpool_add("<src_info>");
 	CIL_KEY_SRC_CIL = cil_strpool_add("<src_cil>");
 	CIL_KEY_SRC_HLL = cil_strpool_add("<src_hll>");
+	CIL_KEY_SANDBOXDENY = cil_strpool_add("deny");
 }
 
 void cil_db_init(struct cil_db **db)
@@ -459,6 +461,7 @@ void cil_db_init(struct cil_db **db)
 	(*db)->mls = -1;
 	(*db)->target_platform = SEPOL_TARGET_SELINUX;
 	(*db)->policy_version = POLICYDB_VERSION_MAX;
+	(*db)->sandbox = 0;
 }
 
 void cil_db_destroy(struct cil_db **db)
@@ -1218,6 +1221,8 @@ const char * cil_node_to_string(struct cil_tree_node *node)
 			return CIL_KEY_DONTAUDIT;
 		case CIL_AVRULE_NEVERALLOW:
 			return CIL_KEY_NEVERALLOW;
+		case CIL_AVRULE_SANDBOXDENY:
+			return CIL_KEY_SANDBOXDENY;
 		default:
 			break;
 		}
@@ -1871,6 +1876,11 @@ void cil_set_policy_version(struct cil_db *db, int policy_version)
 	db->policy_version = policy_version;
 }
 
+void cil_set_sandbox(struct cil_db *db, int sandbox)
+{
+	db->sandbox = sandbox;
+}
+
 void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM])
 {
 	uint32_t i = 0;
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index 62178d99..3e8ba8a2 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -1295,6 +1295,9 @@ int __cil_insert_avrule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t t
 	case CIL_AVRULE_DONTAUDIT:
 		avtab_key.specified = AVTAB_AUDITDENY;
 		break;
+	case CIL_AVRULE_SANDBOXDENY:
+		avtab_key.specified = AVTAB_SANDBOXDENY;
+		break;
 	default:
 		rc = SEPOL_ERR;
 		goto exit;
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
index fcecdc4f..ba56bc80 100644
--- a/libsepol/cil/src/cil_build_ast.c
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -6328,6 +6328,15 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
 	} else if (parse_current->data == CIL_KEY_NEVERALLOW) {
 		rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_NEVERALLOW);
 		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_SANDBOXDENY) {
+		if (!db->sandbox) {
+			cil_log(CIL_ERR, "Error: deny statements permitted only in sandbox\n");
+			rc = SEPOL_ERR;
+		} else {
+			rc = cil_gen_avrule(parse_current, ast_node,
+					    CIL_AVRULE_SANDBOXDENY);
+		}
+		*finished = CIL_TREE_SKIP_NEXT;
 	} else if (parse_current->data == CIL_KEY_ALLOWX) {
 		rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_ALLOWED);
 		*finished = CIL_TREE_SKIP_NEXT;
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
index 9bdcbdd0..065be4d5 100644
--- a/libsepol/cil/src/cil_internal.h
+++ b/libsepol/cil/src/cil_internal.h
@@ -235,6 +235,7 @@ extern char *CIL_KEY_UNORDERED;
 extern char *CIL_KEY_SRC_INFO;
 extern char *CIL_KEY_SRC_CIL;
 extern char *CIL_KEY_SRC_HLL;
+extern char *CIL_KEY_SANDBOXDENY;
 
 /*
 	Symbol Table Array Indices
@@ -321,6 +322,7 @@ struct cil_db {
 	int multiple_decls;
 	int target_platform;
 	int policy_version;
+	int sandbox;
 };
 
 struct cil_root {
@@ -597,7 +599,10 @@ struct cil_tunable {
 #define CIL_AVRULE_AUDITALLOW  2
 #define CIL_AVRULE_DONTAUDIT   8
 #define CIL_AVRULE_NEVERALLOW 128
-#define CIL_AVRULE_AV         (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+#define CIL_AVRULE_SANDBOXDENY 4096
+#define CIL_AVRULE_AV		(AVRULE_ALLOWED | AVRULE_AUDITALLOW | \
+				 AVRULE_DONTAUDIT | AVRULE_NEVERALLOW | \
+				 AVRULE_SANDBOXDENY)
 struct cil_avrule {
 	int is_extended;
 	uint32_t rule_kind;
diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c
index b1cbda91..8ed8d686 100644
--- a/libsepol/cil/src/cil_tree.c
+++ b/libsepol/cil/src/cil_tree.c
@@ -1178,6 +1178,9 @@ void cil_tree_print_node(struct cil_tree_node *node)
 			case CIL_AVRULE_NEVERALLOW:
 				cil_log(CIL_INFO, "NEVERALLOW:");
 				break;
+			case CIL_AVRULE_SANDBOXDENY:
+				cil_log(CIL_INFO, "DENY:");
+				break;
 			}
 
 			if (rule->src != NULL) {
diff --git a/libsepol/include/sepol/policydb.h b/libsepol/include/sepol/policydb.h
index 792913dd..a4d369a3 100644
--- a/libsepol/include/sepol/policydb.h
+++ b/libsepol/include/sepol/policydb.h
@@ -119,6 +119,17 @@ extern int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf);
  */
 extern int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf);
 
+/*
+ * Write a policydb to a sandbox binary file.
+ * The generated image will be in the binary format desgined specifically
+ * for sandboxes.
+ */
+#define SEPOL_SANDBOX_ALLOW 0x00
+#define SEPOL_SANDBOX_DENY 0x01
+extern int sepol_policydb_write_sandbox(sepol_policydb_t *p,
+					sepol_policy_file_t *pf,
+					char *context, int mode);
+
 /*
  * Extract a policydb from a binary policy memory image.  
  * This is equivalent to sepol_policydb_read with a policy file
diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h
index 10ecde9a..0db4f408 100644
--- a/libsepol/include/sepol/policydb/avtab.h
+++ b/libsepol/include/sepol/policydb/avtab.h
@@ -55,7 +55,9 @@ typedef struct avtab_key {
 #define AVTAB_AUDITALLOW	0x0002
 #define AVTAB_AUDITDENY		0x0004
 #define AVTAB_NEVERALLOW	0x0080
-#define AVTAB_AV		(AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_SANDBOXDENY	0x1000
+#define AVTAB_AV		(AVTAB_ALLOWED | AVTAB_AUDITALLOW | \
+				 AVTAB_AUDITDENY | AVTAB_SANDBOXDENY)
 #define AVTAB_TRANSITION	0x0010
 #define AVTAB_MEMBER		0x0020
 #define AVTAB_CHANGE		0x0040
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index 81b63fef..8f97bbcc 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -272,7 +272,10 @@ typedef struct avrule {
 #define AVRULE_AUDITDENY		AVTAB_AUDITDENY
 #define AVRULE_DONTAUDIT		0x0008
 #define AVRULE_NEVERALLOW		AVTAB_NEVERALLOW
-#define AVRULE_AV         (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_AUDITDENY | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+#define AVRULE_SANDBOXDENY              AVTAB_SANDBOXDENY
+#define AVRULE_AV			(AVRULE_ALLOWED | AVRULE_AUDITALLOW | \
+					 AVRULE_AUDITDENY | AVRULE_DONTAUDIT | \
+					 AVRULE_NEVERALLOW | AVRULE_SANDBOXDENY)
 #define AVRULE_TRANSITION		AVTAB_TRANSITION
 #define AVRULE_MEMBER			AVTAB_MEMBER
 #define AVRULE_CHANGE			AVTAB_CHANGE
@@ -723,6 +726,9 @@ extern int avrule_read_list(policydb_t * p, avrule_t ** avrules,
 			    struct policy_file *fp);
 
 extern int policydb_write(struct policydb *p, struct policy_file *pf);
+extern int policydb_write_sandbox(struct policydb *p,
+				  struct policy_file *pf,
+				  char *context, int mode);
 extern int policydb_set_target_platform(policydb_t *p, int platform);
 
 #define PERM_SYMTAB_SIZE 32
diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in
index f4946a79..e4d27d81 100644
--- a/libsepol/src/libsepol.map.in
+++ b/libsepol/src/libsepol.map.in
@@ -50,6 +50,7 @@ LIBSEPOL_1.1 {
 	cil_set_attrs_expand_generated;
 	cil_set_attrs_expand_size;
 	cil_set_multiple_decls;
+	cil_set_sandbox;
 	cil_write_policy_conf;
 	sepol_ppfile_to_module_package;
 	sepol_module_package_to_cil;
diff --git a/libsepol/src/policydb_public.c b/libsepol/src/policydb_public.c
index 747a43ff..b25636f9 100644
--- a/libsepol/src/policydb_public.c
+++ b/libsepol/src/policydb_public.c
@@ -184,6 +184,12 @@ int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf)
 	return policydb_write(&p->p, &pf->pf);
 }
 
+int sepol_policydb_write_sandbox(sepol_policydb_t *p, sepol_policy_file_t *pf,
+				 char *context, int mode)
+{
+	return policydb_write_sandbox(&p->p, &pf->pf, context, mode);
+}
+
 int sepol_policydb_from_image(sepol_handle_t * handle,
 			      void *data, size_t len, sepol_policydb_t * p)
 {
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index 1fd6a16a..eb97700b 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -2332,3 +2332,98 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
 
 	return POLICYDB_SUCCESS;
 }
+
+int policydb_write_sandbox(policydb_t *p, struct policy_file *fp,
+			   char *context, int mode)
+{
+	uint32_t buf[32], config;
+	size_t items, len;
+	struct policy_data pd;
+
+	if (p->unsupported_format)
+		return POLICYDB_UNSUPPORTED;
+
+	pd.fp = fp;
+	pd.p = p;
+
+	config = 0;
+	if (p->mls) {
+		if ((p->policyvers < POLICYDB_VERSION_MLS &&
+		    p->policy_type == POLICY_KERN) ||
+		    (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+		    p->policy_type == POLICY_BASE) ||
+		    (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+		    p->policy_type == POLICY_MOD)) {
+			ERR(fp->handle, "policy version %d cannot support MLS",
+			    p->policyvers);
+			return POLICYDB_ERROR;
+		}
+		config |= POLICYDB_CONFIG_MLS;
+	}
+
+	config |= (POLICYDB_CONFIG_UNKNOWN_MASK & p->handle_unknown);
+
+	/* Write the context length and context */
+	len = strlen(context);
+	buf[0] = cpu_to_le32(len);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	items = put_entry(context, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	/* Write mode */
+	buf[0] = cpu_to_le32(mode);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	/* Write out commons */
+	buf[0] = cpu_to_le32(p->symtab[SYM_COMMONS].nprim);
+	buf[1] = p->symtab[SYM_COMMONS].table->nel;
+	buf[1] = cpu_to_le32(buf[1]);
+	items = put_entry(buf, sizeof(uint32_t), 2, fp);
+	if (items != 2)
+		return POLICYDB_ERROR;
+	if (hashtab_map(p->symtab[SYM_COMMONS].table, write_f[SYM_COMMONS], &pd))
+		return POLICYDB_ERROR;
+
+	/* Write out classes */
+	buf[0] = cpu_to_le32(p->symtab[SYM_CLASSES].nprim);
+	buf[1] = p->symtab[SYM_CLASSES].table->nel;
+	buf[1] = cpu_to_le32(buf[1]);
+	items = put_entry(buf, sizeof(uint32_t), 2, fp);
+	if (items != 2)
+		return POLICYDB_ERROR;
+	if (hashtab_map(p->symtab[SYM_CLASSES].table, write_f[SYM_CLASSES], &pd))
+		return POLICYDB_ERROR;
+
+	/* Write out types */
+	buf[0] = cpu_to_le32(p->symtab[SYM_TYPES].nprim);
+	buf[1] = p->symtab[SYM_TYPES].table->nel;
+
+	/*
+	 * A special case when writing type/attribute symbol table.
+	 * The kernel policy version less than 24 does not support
+	 * to load entries of attribute, so we have to re-calculate
+	 * the actual number of types except for attributes.
+	 */
+	if (p->policyvers < POLICYDB_VERSION_BOUNDARY &&
+	    p->policy_type == POLICY_KERN) {
+		hashtab_map(p->symtab[SYM_TYPES].table,
+			    type_attr_uncount, &buf[1]);
+	}
+	buf[1] = cpu_to_le32(buf[1]);
+	items = put_entry(buf, sizeof(uint32_t), 2, fp);
+	if (items != 2)
+		return POLICYDB_ERROR;
+	if (hashtab_map(p->symtab[SYM_TYPES].table, write_f[SYM_TYPES], &pd))
+		return POLICYDB_ERROR;
+
+	/* Write out te rules */
+	if (avtab_write(p, &p->te_avtab, fp))
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
diff --git a/policycoreutils/.gitignore b/policycoreutils/.gitignore
index 47c9cc52..35963ddf 100644
--- a/policycoreutils/.gitignore
+++ b/policycoreutils/.gitignore
@@ -10,3 +10,4 @@ setfiles/restorecon_xattr
 setfiles/setfiles
 setsebool/setsebool
 hll/pp/pp
+sebox/sebox
diff --git a/policycoreutils/Makefile b/policycoreutils/Makefile
index b930b297..e92a6b53 100644
--- a/policycoreutils/Makefile
+++ b/policycoreutils/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = setfiles load_policy newrole run_init secon sestatus semodule setsebool scripts po man hll
+SUBDIRS = setfiles load_policy newrole run_init secon sestatus semodule setsebool sebox scripts po man hll
 
 all install relabel clean indent:
 	@for subdir in $(SUBDIRS); do \
diff --git a/policycoreutils/sebox/Makefile b/policycoreutils/sebox/Makefile
new file mode 100644
index 00000000..0dd0d540
--- /dev/null
+++ b/policycoreutils/sebox/Makefile
@@ -0,0 +1,28 @@
+# Installation directories.
+PREFIX ?= /usr
+SBINDIR ?= $(PREFIX)/sbin
+MANDIR = $(PREFIX)/share/man
+ETCDIR ?= /etc
+
+CFLAGS ?= -Werror -Wall -W
+override CFLAGS += -D_FILE_OFFSET_BITS=64
+override LDLIBS += -lselinux
+
+all: sebox
+
+sebox: sebox.o
+
+install: all
+	[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
+	-mkdir -p $(DESTDIR)$(SBINDIR)
+	install -m 755 sebox $(DESTDIR)$(SBINDIR)
+	install -m 644 sebox.8 $(DESTDIR)$(MANDIR)/man8
+	-mkdir -p $(DESTDIR)$(ETCDIR)
+
+clean:
+	rm -f sebox *.o
+
+indent:
+	../../scripts/Lindent $(wildcard *.[ch])
+
+relabel:
diff --git a/policycoreutils/sebox/sebox.8 b/policycoreutils/sebox/sebox.8
new file mode 100644
index 00000000..32d73cbc
--- /dev/null
+++ b/policycoreutils/sebox/sebox.8
@@ -0,0 +1,50 @@
+.TH "sebox" "8" "01 Mar 2019" "Security Enhanced Linux" "SELinux command line documentation"
+.SH "NAME"
+sebox \- SELinux sandbox tool
+
+.SH "SYNOPSIS"
+.B sebox
+.I \-l FILE
+.br
+.B sebox
+.I \-u FILE
+.br
+.B sebox
+.I \-L
+
+.SH "DESCRIPTION"
+.sp
+This tool is used to load and unload sandbox policy files into a running SELinux system.
+.RS
+.SH "OPTIONS"
+.B \-l, --load=FILE
+.RS
+Load sandbox policy
+.RE
+.sp
+.B \-u, --unload=FILE
+.RS
+Unload sandbox policy
+.RE
+.sp
+.B \-L, --list
+.RS
+List sandbox policies
+.RE
+.sp
+.B \-v, --verbose
+.RS
+Verbose output
+.RE
+.sp
+.B \-h, --help
+.RS
+Help
+.RE
+.SH "AUTHOR"
+This man page was written by ......
+.br
+The program was written by .......
+
+.SH "SEE ALSO"
+.BR selinux "(8), " sestatus.conf "(5)
diff --git a/policycoreutils/sebox/sebox.c b/policycoreutils/sebox/sebox.c
new file mode 100644
index 00000000..13331d8d
--- /dev/null
+++ b/policycoreutils/sebox/sebox.c
@@ -0,0 +1,200 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <selinux/selinux.h>
+
+#define MODE_LOAD 1
+#define MODE_UNLOAD 2
+#define MODE_LIST 3
+
+#define SELINUXFS_SANDBOX_LOAD "/sys/fs/selinux/sandbox/sandbox_load"
+#define SELINUXFS_SANDBOX_UNLOAD "/sys/fs/selinux/sandbox/sandbox_unload"
+
+extern char *selinux_mnt;
+
+static __attribute__((__noreturn__)) void usage(const char *prog)
+{
+	printf("Usage: %s [OPTIONS]...\n", prog);
+	printf("  %s --load FILE\n", prog);
+	printf("  %s --unload FILE\n", prog);
+	printf("  %s --list\n", prog);
+	printf("\n");
+	printf("Options\n");
+	printf("  -l, --load=<file>              load sandbox policy\n");
+	printf("  -u, --unload=<file>            unload sandbox policy\n");
+	printf("  -L, --list                     list installed sandboxes\n");
+	printf("  -v  --verbose                  verbose\n");
+	printf("  -h, --help                     display usage information\n");
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt = 0;
+	int opt_index = 0;
+	int verbose = 0;
+	int mode = 0;
+	char *filepath = NULL;
+	FILE *file = NULL;
+	struct stat filedata;
+	ssize_t datalen = 0;
+	char *data = NULL;
+	int fd = -1;
+	ssize_t written = 0;
+	static struct option long_opts[] = {
+		{"help", no_argument, 0, 'h'},
+		{"verbose", no_argument, 0, 'v'},
+		{"load", required_argument, 0, 'l'},
+		{"unload", required_argument, 0, 'u'},
+		{"list", no_argument, 0, 'L'},
+		{0, 0, 0, 0}
+	};
+	int rc = 0;
+
+	while (1) {
+
+		opt = getopt_long(argc, argv, "hvl:u:L", long_opts, &opt_index);
+
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+		case 'v':
+			verbose = 1;
+			break;
+		case 'l':
+			if (mode) {
+				fprintf(stderr, "Only one action at a time!\n");
+				usage(argv[0]);
+			}
+			mode = MODE_LOAD;
+			filepath = strdup(optarg);
+			break;
+		case 'u':
+			if (mode) {
+				fprintf(stderr, "Only one action at a time!\n");
+				usage(argv[0]);
+			}
+			mode = MODE_UNLOAD;
+			filepath = strdup(optarg);
+			break;
+		case 'L':
+			if (mode) {
+				fprintf(stderr, "Only one action at a time!\n");
+				usage(argv[0]);
+			}
+			mode = MODE_LIST;
+			break;
+		case 'h':
+			usage(argv[0]);
+			break;
+		default:
+			fprintf(stderr, "Unsupported option %s\n", optarg);
+			usage(argv[0]);
+		}
+
+	}
+
+	if (!mode) {
+		printf("Please specify an action (load/unload/list)\n");
+		return -1;
+	}
+
+	/* make sure selinux is enabled */
+	rc = is_selinux_enabled();
+	if (rc != 1) {
+		printf("SELinux is not enabled\n");
+		printf("Please enable selinux to use sandboxing\n");
+		return -1;
+	}
+
+	/* confirm selinuxfs is mounted */
+	if (selinux_mnt == NULL) {
+		printf("SELinuxfs not mounted\n");
+		printf("Please mount selinuxfs for proper results\n");
+		return -1;
+	}
+
+	/* MODE_LIST doesn't require any input files, handle it first */
+	if (mode == MODE_LIST) {
+		printf("under construction\n");
+		return 0;
+	}
+
+	/* read in file data */
+	file = fopen(filepath, "r");
+	if (!file) {
+		fprintf(stderr, "Could not open file: %s\n", filepath);
+		return -1;
+	}
+
+	rc = stat(filepath, &filedata);
+	if (rc == -1) {
+		fprintf(stderr, "Could not stat file: %s\n", filepath);
+		rc = -1;
+		goto exit;
+	}
+	datalen = filedata.st_size;
+
+	data = malloc(datalen);
+	rc = fread(data, datalen, 1, file);
+	if (rc != 1) {
+		fprintf(stderr, "Failure reading file: %s\n", filepath);
+		rc = -1;
+		goto exit;
+	}
+	fclose(file);
+	file = NULL;
+
+	/* open selinux fs node for writing */
+	if (mode == MODE_LOAD) {
+
+		fd = open(SELINUXFS_SANDBOX_LOAD, O_WRONLY);
+		if (fd < 0) {
+			fprintf(stderr, "Could not open selinuxfs node: %s\n",
+				SELINUXFS_SANDBOX_LOAD);
+			rc = -1;
+			goto exit;
+		}
+
+	} else {
+
+		fd = open(SELINUXFS_SANDBOX_UNLOAD, O_WRONLY);
+		if (fd < 0) {
+			fprintf(stderr, "Could not open selinuxfs node: %s\n",
+				SELINUXFS_SANDBOX_UNLOAD);
+			rc = -1;
+			goto exit;
+		}
+
+	}
+
+	written = write(fd, data, datalen);
+	if (written != datalen) {
+		fprintf(stderr, "Failure writing to selinuxfs node: %s\n",
+			SELINUXFS_SANDBOX_LOAD);
+		rc = -1;
+		goto exit;
+	}
+	close(fd);
+	fd = -1;
+
+	if (verbose)
+		printf("done\n");
+
+	rc = 0;
+
+exit:
+	if (file)
+		fclose(file);
+	if (fd)
+		close(fd);
+	free(data);
+	return rc;
+}
diff --git a/secilc/secilc.c b/secilc/secilc.c
index 186c5a73..b22d93d7 100644
--- a/secilc/secilc.c
+++ b/secilc/secilc.c
@@ -69,6 +69,9 @@ static __attribute__((__noreturn__)) void usage(const char *prog)
 	printf("  -X, --expand-size <SIZE>       Expand type attributes with fewer than <SIZE>\n");
 	printf("                                 members.\n");
 	printf("  -O, --optimize                 optimize final policy\n");
+	printf("  -s, --sandbox=<context>        write a binary sandbox policy file\n");
+	printf("  -a, --sandbox-allow            set sandbox policy in allow mode\n");
+	printf("  -d, --sandbox-deny             set sandbox policy in deny mode (default)\n");
 	printf("  -v, --verbose                  increment verbosity level\n");
 	printf("  -h, --help                     display usage information\n");
 	exit(1);
@@ -86,6 +89,7 @@ int main(int argc, char *argv[])
 	struct stat filedata;
 	uint32_t file_size;
 	char *output = NULL;
+	char *sandbox_context = NULL;
 	char *filecontexts = NULL;
 	struct cil_db *db = NULL;
 	int target = SEPOL_TARGET_SELINUX;
@@ -101,6 +105,8 @@ int main(int argc, char *argv[])
 	int optimize = 0;
 	int opt_char;
 	int opt_index = 0;
+	int sandbox = 0;
+	int sandbox_mode = SEPOL_SANDBOX_DENY;
 	char *fc_buf = NULL;
 	size_t fc_size;
 	enum cil_log_level log_level = CIL_ERR;
@@ -120,12 +126,15 @@ int main(int argc, char *argv[])
 		{"expand-generated", no_argument, 0, 'G'},
 		{"expand-size", required_argument, 0, 'X'},
 		{"optimize", no_argument, 0, 'O'},
+		{"sandbox", required_argument, 0, 's'},
+		{"sandbox-allow", no_argument, 0, 'a'},
+		{"sandbox-deny", no_argument, 0, 'd'},
 		{0, 0, 0, 0}
 	};
 	int i;
 
 	while (1) {
-		opt_char = getopt_long(argc, argv, "o:f:U:hvt:M:PDmNOc:GX:n", long_opts, &opt_index);
+		opt_char = getopt_long(argc, argv, "o:f:U:hvt:M:PDmNOc:GX:s:n", long_opts, &opt_index);
 		if (opt_char == -1) {
 			break;
 		}
@@ -217,6 +226,16 @@ int main(int argc, char *argv[])
 			case 'O':
 				optimize = 1;
 				break;
+			case 's':
+				sandbox_context = strdup(optarg);
+				sandbox = 1;
+				break;
+			case 'a':
+				sandbox_mode = SEPOL_SANDBOX_ALLOW;
+				break;
+			case 'd':
+				sandbox_mode = SEPOL_SANDBOX_DENY;
+				break;
 			case 'h':
 				usage(argv[0]);
 			case '?':
@@ -252,6 +271,7 @@ int main(int argc, char *argv[])
 	if (attrs_expand_size >= 0) {
 		cil_set_attrs_expand_size(db, (unsigned)attrs_expand_size);
 	}
+	cil_set_sandbox(db, sandbox);
 
 	for (i = optind; i < argc; i++) {
 		file = fopen(argv[i], "r");
@@ -338,6 +358,17 @@ int main(int argc, char *argv[])
 
 	sepol_policy_file_set_fp(pf, binary);
 
+	if (sandbox) {
+		rc = sepol_policydb_write_sandbox(pdb, pf, sandbox_context,
+						  sandbox_mode);
+		if (rc != 0) {
+			fprintf(stderr,
+				"Failed to write binary sandbox policy :%d\n",
+				rc);
+		}
+		goto exit;
+	}
+
 	rc = sepol_policydb_write(pdb, pf);
 	if (rc != 0) {
 		fprintf(stderr, "Failed to write binary policy: %d\n", rc);
-- 
2.17.1


                 reply	other threads:[~2020-03-13 13:42 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200313134150.27492-1-stephen.smalley.work@gmail.com \
    --to=stephen.smalley.work@gmail.com \
    --cc=paul@paul-moore.com \
    --cc=sds@tycho.nsa.gov \
    --cc=selinux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.