From 50640d313dca7d783d3edece1ba140b4afdc9d9c Mon Sep 17 00:00:00 2001 From: Richard Haines Date: Thu, 13 Aug 2015 12:09:00 +0100 Subject: [PATCH] libselinux: Add policy context validation to sefcontext_compile Add -p option that will take a binary policy file to validate context entries in the text file_contexts file. Should validation fail the binary file will not be written. Signed-off-by: Richard Haines --- libselinux/man/man8/sefcontext_compile.8 | 15 ++++- libselinux/utils/Makefile | 2 +- libselinux/utils/sefcontext_compile.c | 72 ++++++++++++++++++++---- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/libselinux/man/man8/sefcontext_compile.8 b/libselinux/man/man8/sefcontext_compile.8 index 584c4c67..b77ff3a1 100644 --- a/libselinux/man/man8/sefcontext_compile.8 +++ b/libselinux/man/man8/sefcontext_compile.8 @@ -1,4 +1,4 @@ -.TH "sefcontext_compile" "8" "12 Jun 2015" "dwalsh@redhat.com" "SELinux Command Line documentation" +.TH "sefcontext_compile" "8" "12 Aug 2015" "dwalsh@redhat.com" "SELinux Command Line documentation" .SH "NAME" sefcontext_compile \- compile file context regular expression files . @@ -6,6 +6,8 @@ sefcontext_compile \- compile file context regular expression files .B sefcontext_compile .RB [ \-o .IR outputfile ] +.RB [ \-p +.IR policyfile ] .I inputfile . .SH "DESCRIPTION" @@ -29,7 +31,16 @@ Specify an that must be a fully qualified file name as the .B .bin suffix is not automatically added. -. +.TP +.B \-p +Specify a binary +.I policyfile +that will be used to validate the context entries in the +.I inputfile +.br +If an invalid context is found the pcre formatted file will not be written and +an error will be returned. + .SH "RETURN VALUE" On error -1 is returned. On success 0 is returned. diff --git a/libselinux/utils/Makefile b/libselinux/utils/Makefile index c36761de..cac85c75 100644 --- a/libselinux/utils/Makefile +++ b/libselinux/utils/Makefile @@ -28,7 +28,7 @@ LDLIBS += -L../src -lselinux -L$(LIBDIR) TARGETS=$(patsubst %.c,%,$(wildcard *.c)) -sefcontext_compile: LDLIBS += -lpcre ../src/libselinux.a +sefcontext_compile: LDLIBS += -lpcre ../src/libselinux.a -lsepol ifeq ($(DISABLE_AVC),y) UNUSED_TARGETS+=compute_av compute_create compute_member compute_relabel diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c index 41606328..d2578b6b 100644 --- a/libselinux/utils/sefcontext_compile.c +++ b/libselinux/utils/sefcontext_compile.c @@ -10,11 +10,22 @@ #include #include #include +#include #include "../src/label_file.h" -static int validate_context(char __attribute__ ((unused)) **ctx) +const char *policy_file; +static int ctx_err; + +static int validate_context(char **ctxp) { + char *ctx = *ctxp; + + if (policy_file && sepol_check_context(ctx) < 0) { + ctx_err = -1; + return ctx_err; + } + return 0; } @@ -38,8 +49,15 @@ static int process_file(struct selabel_handle *rec, const char *filename) rc = 0; while (getline(&line_buf, &line_len, context_file) > 0) { rc = process_line(rec, filename, prefix, line_buf, ++line_num); - if (rc) + if (rc || ctx_err) { + /* With -p option need to check and fail if ctx err as + * process_line() context validation on Linux does not + * return an error, but does print the error line to + * stderr. Android will set both to error and print + * the error line. */ + rc = -1; goto out; + } } out: free(line_buf); @@ -263,13 +281,15 @@ static void free_specs(struct saved_data *data) static void usage(const char *progname) { fprintf(stderr, - "usage: %s [-o out_file] fc_file\n" - "Where:\n\t" - "-o Optional file name of the PCRE formatted binary\n\t" - " file to be output. If not specified the default\n\t" - " will be fc_file with the .bin suffix appended.\n\t" - "fc_file The text based file contexts file to be processed.\n", - progname); + "usage: %s [-o out_file] [-p policy_file] fc_file\n" + "Where:\n\t" + "-o Optional file name of the PCRE formatted binary\n\t" + " file to be output. If not specified the default\n\t" + " will be fc_file with the .bin suffix appended.\n\t" + "-p Optional binary policy file that will be used to\n\t" + " validate contexts defined in the fc_file.\n\t" + "fc_file The text based file contexts file to be processed.\n", + progname); exit(EXIT_FAILURE); } @@ -280,6 +300,7 @@ int main(int argc, char *argv[]) char stack_path[PATH_MAX + 1]; char *tmp = NULL; int fd, rc, opt; + FILE *policy_fp = NULL; struct stat buf; struct selabel_handle *rec = NULL; struct saved_data *data = NULL; @@ -287,11 +308,14 @@ int main(int argc, char *argv[]) if (argc < 2) usage(argv[0]); - while ((opt = getopt(argc, argv, "o:")) > 0) { + while ((opt = getopt(argc, argv, "o:p:")) > 0) { switch (opt) { case 'o': out_file = optarg; break; + case 'p': + policy_file = optarg; + break; default: usage(argv[0]); } @@ -306,10 +330,30 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + /* Open binary policy if supplied. */ + if (policy_file) { + policy_fp = fopen(policy_file, "r"); + + if (!policy_fp) { + fprintf(stderr, "Failed to open policy: %s\n", + policy_file); + exit(EXIT_FAILURE); + } + + if (sepol_set_policydb_from_file(policy_fp) < 0) { + fprintf(stderr, "Failed to load policy: %s\n", + policy_file); + fclose(policy_fp); + exit(EXIT_FAILURE); + } + } + /* Generate dummy handle for process_line() function */ rec = (struct selabel_handle *)calloc(1, sizeof(*rec)); if (!rec) { fprintf(stderr, "Failed to calloc handle\n"); + if (policy_fp) + fclose(policy_fp); exit(EXIT_FAILURE); } rec->backend = SELABEL_CTX_FILE; @@ -318,7 +362,8 @@ int main(int argc, char *argv[]) * process_line function, however as the bin file being generated * may not be related to the currently loaded policy (that it * would be validated against), then set callback to ignore any - * validation. */ + * validation - unless the -p option is used in which case if an + * error is detected, the process will be aborted. */ rec->validating = 1; selinux_set_callback(SELINUX_CB_VALIDATE, (union selinux_callback)&validate_context); @@ -327,6 +372,8 @@ int main(int argc, char *argv[]) if (!data) { fprintf(stderr, "Failed to calloc saved_data\n"); free(rec); + if (policy_fp) + fclose(policy_fp); exit(EXIT_FAILURE); } @@ -376,6 +423,9 @@ int main(int argc, char *argv[]) rc = 0; out: + if (policy_fp) + fclose(policy_fp); + free_specs(data); free(rec); free(data);