From 922b4e95220de78f18335a79de6188dd4f4f9911 Mon Sep 17 00:00:00 2001
From: William Roberts <william.c.roberts@intel.com>
Date: Thu, 14 Jan 2016 17:06:37 -0800
Subject: [PATCH] checkfc: do not die on 0 length fc's

Checkfc was treating 0 size fc files as a fatal error.
An empty fc file should be treated as "nothing to check"
so long as the -e option is passed.

We add this option, so we don't allow empty file_context
files to pass CTS checking.

Change-Id: Ibca6bd948a13389e10c605d613acc48c5504443e
Signed-off-by: William Roberts <william.c.roberts@intel.com>
---
 tools/checkfc.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/tools/checkfc.c b/tools/checkfc.c
index 602a05f76..e7d19b02b 100644
--- a/tools/checkfc.c
+++ b/tools/checkfc.c
@@ -3,11 +3,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <sepol/module.h>
 #include <sepol/policydb/policydb.h>
 #include <sepol/sepol.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 static const char * const CHECK_FC_ASSERT_ATTRS[] = { "fs_type", "dev_type", "file_type", NULL };
 static const char * const CHECK_PC_ASSERT_ATTRS[] = { "property_type", NULL };
@@ -182,10 +185,11 @@ static int validate(char **contextp)
 }
 
 static void usage(char *name) {
-    fprintf(stderr, "usage1:  %s [-p|-s] sepolicy context_file\n\n"
+    fprintf(stderr, "usage1:  %s [-p|-s] [-e] sepolicy context_file\n\n"
         "Parses a context file and checks for syntax errors.\n"
         "The context_file is assumed to be a file_contexts file\n"
-        "unless the -p or -s option is used to indicate the property or service backend respectively.\n\n"
+        "unless the -p or -s option is used to indicate the property or service backend respectively.\n"
+        "If -e is specified, then the context_file is allowed to be empty.\n\n"
 
         "usage2:  %s -c file_contexts1 file_contexts2\n\n"
         "Compares two file contexts files and reports one of subset, equal, superset, or incomparable.\n\n",
@@ -244,8 +248,22 @@ static void do_compare_and_die_on_error(struct selinux_opt opts[], unsigned int
 }
 
 static void do_fc_check_and_die_on_error(struct selinux_opt opts[], unsigned int backend, filemode mode,
-        const char *sepolicy_file, const char *context_file)
+        const char *sepolicy_file, const char *context_file, bool allow_empty)
 {
+    struct stat sb;
+    if (stat(context_file, &sb) < 0) {
+        perror("Error: could not get stat on file contexts file");
+        exit(1);
+    }
+
+    if (sb.st_size == 0) {
+        /* Nothing to check on empty file_contexts file if allowed*/
+        if (allow_empty) {
+            return;
+        }
+        /* else: We could throw the error here, but libselinux backend will catch it */
+    }
+
     global_state.sepolicy.file = fopen(sepolicy_file, "r");
     if (!global_state.sepolicy.file) {
       perror("Error: could not open policy file");
@@ -308,16 +326,20 @@ int main(int argc, char **argv)
   // Default backend unless changed by input argument.
   unsigned int backend = SELABEL_CTX_FILE;
 
+  bool allow_empty = false;
   bool compare = false;
   char c;
 
   filemode mode = filemode_file_contexts;
 
-  while ((c = getopt(argc, argv, "cps")) != -1) {
+  while ((c = getopt(argc, argv, "cpse")) != -1) {
     switch (c) {
       case 'c':
         compare = true;
         break;
+      case 'e':
+        allow_empty = true;
+        break;
       case 'p':
         mode = filemode_property_contexts;
         backend = SELABEL_CTX_ANDROID_PROP;
@@ -351,7 +373,7 @@ int main(int argc, char **argv)
       char *sepolicy_file = argv[index];
       char *context_file = argv[index + 1];
 
-      do_fc_check_and_die_on_error(opts, backend, mode, sepolicy_file, context_file);
+      do_fc_check_and_die_on_error(opts, backend, mode, sepolicy_file, context_file, allow_empty);
   }
   exit(0);
 }
-- 
GitLab