Update OTA installer to understand SELinux filesystem labels

Modify the OTA installer to understand SELinux filesystem labels.

We do this by introducing new set_perm2 / set_perm2_recursive
calls, which understand SELinux filesystem labels. These filesystem
labels are applied at the same time that we apply the
UID / GID / permission changes.

For compatibility, we preserve the behavior of the existing
set_perm / set_perm_recursive calls.

If the destination kernel doesn't support security labels, don't
fail. SELinux isn't enabled on all kernels.

Bug: 8985290
Change-Id: I99800499f01784199e4918a82e3e2db1089cf25b
diff --git a/updater/install.c b/updater/install.c
index 9fa06a2..c81bbb5 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <time.h>
+#include <selinux/selinux.h>
 
 #include "cutils/misc.h"
 #include "cutils/properties.h"
@@ -521,9 +522,10 @@
 
 Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
     char* result = NULL;
-    bool recursive = (strcmp(name, "set_perm_recursive") == 0);
+    bool recursive = (strcmp(name, "set_perm_recursive") == 0) || (strcmp(name, "set_perm2_recursive") == 0);
+    bool has_selabel = (strcmp(name, "set_perm2") == 0) || (strcmp(name, "set_perm2_recursive") == 0);
 
-    int min_args = 4 + (recursive ? 1 : 0);
+    int min_args = 4 + (has_selabel ? 1 : 0) + (recursive ? 1 : 0);
     if (argc < min_args) {
         return ErrorAbort(state, "%s() expects %d+ args, got %d",
                           name, min_args, argc);
@@ -562,8 +564,13 @@
             goto done;
         }
 
-        for (i = 4; i < argc; ++i) {
-            dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
+        char* secontext = NULL;
+        if (has_selabel) {
+            secontext = args[4];
+        }
+
+        for (i = 4 + (has_selabel ? 1 : 0); i < argc; ++i) {
+            dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode, secontext);
         }
     } else {
         int mode = strtoul(args[2], &end, 0);
@@ -572,7 +579,12 @@
             goto done;
         }
 
-        for (i = 3; i < argc; ++i) {
+        char* secontext = NULL;
+        if (has_selabel) {
+            secontext = args[3];
+        }
+
+        for (i = 3 + (has_selabel ? 1 : 0); i < argc; ++i) {
             if (chown(args[i], uid, gid) < 0) {
                 printf("%s: chown of %s to %d %d failed: %s\n",
                         name, args[i], uid, gid, strerror(errno));
@@ -583,6 +595,11 @@
                         name, args[i], mode, strerror(errno));
                 ++bad;
             }
+            if (has_selabel && lsetfilecon(args[i], secontext) && (errno != ENOTSUP)) {
+                printf("%s: lsetfilecon of %s to %s failed: %s\n",
+                        name, args[i], secontext, strerror(errno));
+                ++bad;
+            }
         }
     }
     result = strdup("");
@@ -1135,6 +1152,8 @@
     RegisterFunction("symlink", SymlinkFn);
     RegisterFunction("set_perm", SetPermFn);
     RegisterFunction("set_perm_recursive", SetPermFn);
+    RegisterFunction("set_perm2", SetPermFn);
+    RegisterFunction("set_perm2_recursive", SetPermFn);
 
     RegisterFunction("getprop", GetPropFn);
     RegisterFunction("file_getprop", FileGetPropFn);