aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-07 23:14:25 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-07 23:14:25 +0000
commitc5f26e712b5fde58fd7b0b242117c3b1736c65e3 (patch)
treeb64a0754c3ae72d8226515e751b4668a6d6c6ba1
parentb3b2052b274d2dfe01886772853362c66a981af5 (diff)
parentbec99f419003e3228ccd785362882d18c730b4fd (diff)
downloadselinux-sdk-release.tar.gz
Snap for 11812660 from bec99f419003e3228ccd785362882d18c730b4fd to sdk-releasesdk-release
Change-Id: I95a9963bc4138da5adcccad407eab38f50e6291e
-rw-r--r--libselinux/src/android/android.c195
-rw-r--r--libselinux/src/android/android_device.c1042
-rw-r--r--libselinux/src/android/android_internal.h21
-rw-r--r--libselinux/src/android/android_unittest.cpp58
4 files changed, 698 insertions, 618 deletions
diff --git a/libselinux/src/android/android.c b/libselinux/src/android/android.c
index 83066118..1b78c8f1 100644
--- a/libselinux/src/android/android.c
+++ b/libselinux/src/android/android.c
@@ -1,4 +1,5 @@
#include <errno.h>
+#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -188,6 +189,200 @@ struct selabel_handle* selinux_android_keystore2_key_context_handle(void)
return context_handle(SELABEL_CTX_ANDROID_KEYSTORE2_KEY, &keystore2_context_paths, "keystore2");
}
+/* The contents of these paths are encrypted on FBE devices until user
+ * credentials are presented (filenames inside are mangled), so we need
+ * to delay restorecon of those until vold explicitly requests it. */
+// NOTE: these paths need to be kept in sync with vold
+#define DATA_SYSTEM_CE_PATH "/data/system_ce"
+#define DATA_VENDOR_CE_PATH "/data/vendor_ce"
+#define DATA_MISC_CE_PATH "/data/misc_ce"
+
+/* The path prefixes of package data directories. */
+#define DATA_DATA_PATH "/data/data"
+#define DATA_USER_PATH "/data/user"
+#define DATA_USER_DE_PATH "/data/user_de"
+#define DATA_MISC_DE_PATH "/data/misc_de"
+#define DATA_STORAGE_AREA_PATH "/data/storage_area"
+#define SDK_SANDBOX_DATA_CE_PATH "/data/misc_ce/*/sdksandbox"
+#define SDK_SANDBOX_DATA_DE_PATH "/data/misc_de/*/sdksandbox"
+
+#define EXPAND_MNT_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?"
+#define EXPAND_USER_PATH EXPAND_MNT_PATH "/user"
+#define EXPAND_USER_DE_PATH EXPAND_MNT_PATH "/user_de"
+#define EXPAND_SDK_CE_PATH EXPAND_MNT_PATH "/misc_ce/*/sdksandbox"
+#define EXPAND_SDK_DE_PATH EXPAND_MNT_PATH "/misc_de/*/sdksandbox"
+
+#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
+#define DATA_USER_PREFIX DATA_USER_PATH "/"
+#define DATA_USER_DE_PREFIX DATA_USER_DE_PATH "/"
+#define DATA_STORAGE_AREA_PREFIX DATA_STORAGE_AREA_PATH "/"
+#define DATA_MISC_CE_PREFIX DATA_MISC_CE_PATH "/"
+#define DATA_MISC_DE_PREFIX DATA_MISC_DE_PATH "/"
+#define EXPAND_MNT_PATH_PREFIX EXPAND_MNT_PATH "/"
+
+bool is_app_data_path(const char *pathname) {
+ int flags = FNM_LEADING_DIR|FNM_PATHNAME;
+#ifdef SELINUX_FLAGS_DATA_DATA_IGNORE
+ if (!strcmp(pathname, DATA_DATA_PATH)) {
+ return true;
+ }
+#endif
+ return (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
+ !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
+ !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
+ !strncmp(pathname, DATA_STORAGE_AREA_PREFIX, sizeof(DATA_STORAGE_AREA_PREFIX)-1) ||
+ !fnmatch(EXPAND_USER_PATH, pathname, flags) ||
+ !fnmatch(EXPAND_USER_DE_PATH, pathname, flags) ||
+ !fnmatch(SDK_SANDBOX_DATA_CE_PATH, pathname, flags) ||
+ !fnmatch(SDK_SANDBOX_DATA_DE_PATH, pathname, flags) ||
+ !fnmatch(EXPAND_SDK_CE_PATH, pathname, flags) ||
+ !fnmatch(EXPAND_SDK_DE_PATH, pathname, flags));
+}
+
+bool is_credential_encrypted_path(const char *pathname) {
+ return !strncmp(pathname, DATA_SYSTEM_CE_PATH, sizeof(DATA_SYSTEM_CE_PATH)-1) ||
+ !strncmp(pathname, DATA_MISC_CE_PATH, sizeof(DATA_MISC_CE_PATH)-1) ||
+ !strncmp(pathname, DATA_VENDOR_CE_PATH, sizeof(DATA_VENDOR_CE_PATH)-1);
+}
+
+/*
+ * Extract the userid from a path.
+ * On success, pathname is updated past the userid.
+ * Returns 0 on success, -1 on error
+ */
+static int extract_userid(const char **pathname, unsigned int *userid)
+{
+ char *end = NULL;
+
+ errno = 0;
+ *userid = strtoul(*pathname, &end, 10);
+ if (errno) {
+ selinux_log(SELINUX_ERROR, "SELinux: Could not parse userid %s: %s.\n",
+ *pathname, strerror(errno));
+ return -1;
+ }
+ if (*pathname == end) {
+ return -1;
+ }
+ if (*userid > 1000) {
+ return -1;
+ }
+ *pathname = end;
+ return 0;
+}
+
+int extract_pkgname_and_userid(const char *pathname, char **pkgname, unsigned int *userid)
+{
+ char *end = NULL;
+
+ if (pkgname == NULL || *pkgname != NULL || userid == NULL) {
+ errno = EINVAL;
+ return -2;
+ }
+
+ /* Skip directory prefix before package name. */
+ if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
+ pathname += sizeof(DATA_DATA_PREFIX) - 1;
+ } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
+ pathname += sizeof(DATA_USER_PREFIX) - 1;
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (*pathname == '/')
+ pathname++;
+ else
+ return -1;
+ } else if (!strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1)) {
+ pathname += sizeof(DATA_USER_DE_PREFIX) - 1;
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (*pathname == '/')
+ pathname++;
+ else
+ return -1;
+ } else if (!strncmp(pathname, DATA_STORAGE_AREA_PREFIX, sizeof(DATA_STORAGE_AREA_PREFIX)-1)) {
+ pathname += sizeof(DATA_STORAGE_AREA_PREFIX) - 1;
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (*pathname == '/')
+ pathname++;
+ else
+ return -1;
+ } else if (!fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
+ pathname += sizeof(EXPAND_USER_PATH);
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (*pathname == '/')
+ pathname++;
+ else
+ return -1;
+ } else if (!fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
+ pathname += sizeof(EXPAND_USER_DE_PATH);
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (*pathname == '/')
+ pathname++;
+ else
+ return -1;
+ } else if (!strncmp(pathname, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1)) {
+ pathname += sizeof(DATA_MISC_CE_PREFIX) - 1;
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
+ pathname += sizeof("/sdksandbox/") - 1;
+ else
+ return -1;
+ } else if (!strncmp(pathname, DATA_MISC_DE_PREFIX, sizeof(DATA_MISC_DE_PREFIX)-1)) {
+ pathname += sizeof(DATA_MISC_DE_PREFIX) - 1;
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
+ pathname += sizeof("/sdksandbox/") - 1;
+ else
+ return -1;
+ } else if (!fnmatch(EXPAND_SDK_CE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
+ pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
+ pathname += sizeof("misc_ce/") - 1;
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
+ pathname += sizeof("/sdksandbox/") - 1;
+ else
+ return -1;
+ } else if (!fnmatch(EXPAND_SDK_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
+ pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
+ pathname += sizeof("misc_de/") - 1;
+ int rc = extract_userid(&pathname, userid);
+ if (rc)
+ return -1;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
+ pathname += sizeof("/sdksandbox/") - 1;
+ else
+ return -1;
+ } else
+ return -1;
+
+ if (!(*pathname))
+ return -1;
+
+ *pkgname = strdup(pathname);
+ if (!(*pkgname))
+ return -2;
+
+ // Trim pkgname.
+ for (end = *pkgname; *end && *end != '/'; end++);
+ *end = '\0';
+
+ return 0;
+}
+
static void __selinux_log_callback(bool add_to_event_log, int type, const char *fmt, va_list ap) {
int priority;
char *strp;
diff --git a/libselinux/src/android/android_device.c b/libselinux/src/android/android_device.c
index df110739..3759b6ec 100644
--- a/libselinux/src/android/android_device.c
+++ b/libselinux/src/android/android_device.c
@@ -155,8 +155,8 @@ static struct selabel_handle *fc_sehandle = NULL;
static void file_context_init(void)
{
- if (!fc_sehandle)
- fc_sehandle = selinux_android_file_context_handle();
+ if (!fc_sehandle)
+ fc_sehandle = selinux_android_file_context_handle();
}
static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
@@ -169,59 +169,59 @@ static struct pkg_info *pkgTab[PKGTAB_SIZE];
/* Returns a hash based on the package name */
static unsigned int pkghash(const char *pkgname)
{
- unsigned int h = 7;
- for (; *pkgname; pkgname++) {
- h = h * 31 + *pkgname;
- }
- return h & (PKGTAB_SIZE - 1);
+ unsigned int h = 7;
+ for (; *pkgname; pkgname++) {
+ h = h * 31 + *pkgname;
+ }
+ return h & (PKGTAB_SIZE - 1);
}
/* Adds the pkg_info entry to the hash table */
static bool pkg_parse_callback(pkg_info *info, void *userdata) {
- (void) userdata;
+ (void) userdata;
- unsigned int hash = pkghash(info->name);
- if (pkgTab[hash])
- /* Collision. Prepend the entry. */
- info->private_data = pkgTab[hash];
- pkgTab[hash] = info;
- return true;
+ unsigned int hash = pkghash(info->name);
+ if (pkgTab[hash])
+ /* Collision. Prepend the entry. */
+ info->private_data = pkgTab[hash];
+ pkgTab[hash] = info;
+ return true;
}
/* Initialize the pkg_info hash table */
static void package_info_init(void)
{
- bool rc = packagelist_parse(pkg_parse_callback, NULL);
- if (!rc) {
- selinux_log(SELINUX_ERROR, "SELinux: Could NOT parse package list\n");
- return;
- }
+ bool rc = packagelist_parse(pkg_parse_callback, NULL);
+ if (!rc) {
+ selinux_log(SELINUX_ERROR, "SELinux: Could NOT parse package list\n");
+ return;
+ }
#if DEBUG
- {
- unsigned int hash, buckets, entries, chainlen, longestchain;
- struct pkg_info *info = NULL;
-
- buckets = entries = longestchain = 0;
- for (hash = 0; hash < PKGTAB_SIZE; hash++) {
- if (pkgTab[hash]) {
- buckets++;
- chainlen = 0;
- for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
- chainlen++;
- selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
- __FUNCTION__,
- info->name, info->uid, info->debuggable ? "true" : "false", info->data_dir, info->seinfo);
- }
- entries += chainlen;
- if (longestchain < chainlen)
- longestchain = chainlen;
- }
- }
- selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
- }
+ {
+ unsigned int hash, buckets, entries, chainlen, longestchain;
+ struct pkg_info *info = NULL;
+
+ buckets = entries = longestchain = 0;
+ for (hash = 0; hash < PKGTAB_SIZE; hash++) {
+ if (pkgTab[hash]) {
+ buckets++;
+ chainlen = 0;
+ for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
+ chainlen++;
+ selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
+ __FUNCTION__,
+ info->name, info->uid, info->debuggable ? "true" : "false", info->data_dir, info->seinfo);
+ }
+ entries += chainlen;
+ if (longestchain < chainlen)
+ longestchain = chainlen;
+ }
+ }
+ selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
+ }
#endif
}
@@ -231,637 +231,443 @@ static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
/* Returns the pkg_info for a package with a specific name */
struct pkg_info *package_info_lookup(const char *name)
{
- struct pkg_info *info;
- unsigned int hash;
+ struct pkg_info *info;
+ unsigned int hash;
- __selinux_once(pkg_once, package_info_init);
+ __selinux_once(pkg_once, package_info_init);
- hash = pkghash(name);
- for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
- if (!strcmp(name, info->name))
- return info;
- }
- return NULL;
+ hash = pkghash(name);
+ for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
+ if (!strcmp(name, info->name))
+ return info;
+ }
+ return NULL;
}
-/* The contents of these paths are encrypted on FBE devices until user
- * credentials are presented (filenames inside are mangled), so we need
- * to delay restorecon of those until vold explicitly requests it. */
-// NOTE: these paths need to be kept in sync with vold
-#define DATA_SYSTEM_CE_PATH "/data/system_ce"
-#define DATA_VENDOR_CE_PATH "/data/vendor_ce"
-#define DATA_MISC_CE_PATH "/data/misc_ce"
-#define DATA_MISC_DE_PATH "/data/misc_de"
-
-/* The path prefixes of package data directories. */
-#define DATA_DATA_PATH "/data/data"
-#define DATA_USER_PATH "/data/user"
-#define DATA_USER_DE_PATH "/data/user_de"
-#define DATA_STORAGE_AREA_PATH "/data/storage_area"
#define USER_PROFILE_PATH "/data/misc/profiles/cur/*"
-#define SDK_SANDBOX_DATA_CE_PATH "/data/misc_ce/*/sdksandbox"
-#define SDK_SANDBOX_DATA_DE_PATH "/data/misc_de/*/sdksandbox"
-
-#define EXPAND_MNT_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?"
-#define EXPAND_USER_PATH EXPAND_MNT_PATH "/user"
-#define EXPAND_USER_DE_PATH EXPAND_MNT_PATH "/user_de"
-#define EXPAND_SDK_CE_PATH EXPAND_MNT_PATH "/misc_ce/*/sdksandbox"
-#define EXPAND_SDK_DE_PATH EXPAND_MNT_PATH "/misc_de/*/sdksandbox"
-
-#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
-#define DATA_USER_PREFIX DATA_USER_PATH "/"
-#define DATA_USER_DE_PREFIX DATA_USER_DE_PATH "/"
-#define DATA_STORAGE_AREA_PREFIX DATA_STORAGE_AREA_PATH "/"
-#define DATA_MISC_CE_PREFIX DATA_MISC_CE_PATH "/"
-#define DATA_MISC_DE_PREFIX DATA_MISC_DE_PATH "/"
-#define EXPAND_MNT_PATH_PREFIX EXPAND_MNT_PATH "/"
-
-/*
- * This method helps in identifying paths that refer to users' app data. Labeling for app data is
- * based on seapp_contexts and seinfo assignments rather than file_contexts and is managed by
- * installd rather than by init.
- */
-static bool is_app_data_path(const char *pathname) {
- int flags = FNM_LEADING_DIR|FNM_PATHNAME;
-#ifdef SELINUX_FLAGS_DATA_DATA_IGNORE
- if (!strcmp(pathname, DATA_DATA_PATH)) {
- return true;
- }
-#endif
- return (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
- !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
- !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
- !strncmp(pathname, DATA_STORAGE_AREA_PREFIX, sizeof(DATA_STORAGE_AREA_PREFIX)-1) ||
- !fnmatch(EXPAND_USER_PATH, pathname, flags) ||
- !fnmatch(EXPAND_USER_DE_PATH, pathname, flags) ||
- !fnmatch(SDK_SANDBOX_DATA_CE_PATH, pathname, flags) ||
- !fnmatch(SDK_SANDBOX_DATA_DE_PATH, pathname, flags) ||
- !fnmatch(EXPAND_SDK_CE_PATH, pathname, flags) ||
- !fnmatch(EXPAND_SDK_DE_PATH, pathname, flags));
-}
-/*
- * Extract the userid from a path.
- * On success, pathname is updated past the userid.
- * Returns 0 on success, -1 on error
- */
-static int extract_userid(const char **pathname, unsigned int *userid)
+static int pkgdir_selabel_lookup(const char *pathname,
+ const char *seinfo,
+ uid_t uid,
+ char **secontextp)
{
- char *end = NULL;
-
- errno = 0;
- *userid = strtoul(*pathname, &end, 10);
- if (errno) {
- selinux_log(SELINUX_ERROR, "SELinux: Could not parse userid %s: %s.\n",
- *pathname, strerror(errno));
- return -1;
- }
- if (*pathname == end) {
- return -1;
- }
- if (*userid > 1000) {
- return -1;
- }
- *pathname = end;
- return 0;
-}
+ char *pkgname = NULL;
+ struct pkg_info *info = NULL;
+ const char *orig_ctx_str = *secontextp;
+ const char *ctx_str = NULL;
+ context_t ctx = NULL;
+ int rc = 0;
+ unsigned int userid_from_path = 0;
+
+ rc = extract_pkgname_and_userid(pathname, &pkgname, &userid_from_path);
+ if (rc) {
+ /* Invalid path, we skip it */
+ if (rc == -1) {
+ return 0;
+ }
+ return rc;
+ }
-/* Extract the pkgname and userid from a path.
- * On success, the caller is responsible for free'ing pkgname.
- * Returns 0 on success, -1 on invalid path, -2 on error.
- */
-static int extract_pkgname_and_userid(const char *pathname, char **pkgname, unsigned int *userid)
-{
- char *end = NULL;
-
- if (pkgname == NULL || *pkgname != NULL || userid == NULL) {
- errno = EINVAL;
- return -2;
- }
-
- /* Skip directory prefix before package name. */
- if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
- pathname += sizeof(DATA_DATA_PREFIX) - 1;
- } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
- pathname += sizeof(DATA_USER_PREFIX) - 1;
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (*pathname == '/')
- pathname++;
- else
- return -1;
- } else if (!strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1)) {
- pathname += sizeof(DATA_USER_DE_PREFIX) - 1;
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (*pathname == '/')
- pathname++;
- else
- return -1;
- } else if (!strncmp(pathname, DATA_STORAGE_AREA_PREFIX, sizeof(DATA_STORAGE_AREA_PREFIX)-1)) {
- pathname += sizeof(DATA_STORAGE_AREA_PREFIX) - 1;
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (*pathname == '/')
- pathname++;
- else
- return -1;
- } else if (!fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
- pathname += sizeof(EXPAND_USER_PATH);
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (*pathname == '/')
- pathname++;
- else
- return -1;
- } else if (!fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
- pathname += sizeof(EXPAND_USER_DE_PATH);
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (*pathname == '/')
- pathname++;
- else
- return -1;
- } else if (!strncmp(pathname, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1)) {
- pathname += sizeof(DATA_MISC_CE_PREFIX) - 1;
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
- pathname += sizeof("/sdksandbox/") - 1;
- else
- return -1;
- } else if (!strncmp(pathname, DATA_MISC_DE_PREFIX, sizeof(DATA_MISC_DE_PREFIX)-1)) {
- pathname += sizeof(DATA_MISC_DE_PREFIX) - 1;
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
- pathname += sizeof("/sdksandbox/") - 1;
- else
- return -1;
- } else if (!fnmatch(EXPAND_SDK_CE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
- pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
- pathname += sizeof("misc_ce/") - 1;
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
- pathname += sizeof("/sdksandbox/") - 1;
- else
- return -1;
- } else if (!fnmatch(EXPAND_SDK_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
- pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
- pathname += sizeof("misc_de/") - 1;
- int rc = extract_userid(&pathname, userid);
- if (rc)
- return -1;
- if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
- pathname += sizeof("/sdksandbox/") - 1;
- else
- return -1;
- } else
- return -1;
-
- if (!(*pathname))
- return -1;
-
- *pkgname = strdup(pathname);
- if (!(*pkgname))
- return -2;
-
- // Trim pkgname.
- for (end = *pkgname; *end && *end != '/'; end++);
- *end = '\0';
-
- return 0;
-}
+ if (!seinfo) {
+ info = package_info_lookup(pkgname);
+ if (!info) {
+ selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n",
+ pkgname, pathname);
+ free(pkgname);
+ return -1;
+ }
+ // info->uid only contains the appid and not the userid.
+ info->uid += userid_from_path * AID_USER_OFFSET;
+ }
-static int pkgdir_selabel_lookup(const char *pathname,
- const char *seinfo,
- uid_t uid,
- char **secontextp)
-{
- char *pkgname = NULL;
- struct pkg_info *info = NULL;
- const char *orig_ctx_str = *secontextp;
- const char *ctx_str = NULL;
- context_t ctx = NULL;
- int rc = 0;
- unsigned int userid_from_path = 0;
-
- rc = extract_pkgname_and_userid(pathname, &pkgname, &userid_from_path);
- if (rc) {
- /* Invalid path, we skip it */
- if (rc == -1) {
- return 0;
- }
- return rc;
- }
-
- if (!seinfo) {
- info = package_info_lookup(pkgname);
- if (!info) {
- selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n",
- pkgname, pathname);
- free(pkgname);
- return -1;
- }
- // info->uid only contains the appid and not the userid.
- info->uid += userid_from_path * AID_USER_OFFSET;
- }
-
- ctx = context_new(orig_ctx_str);
- if (!ctx)
- goto err;
-
- rc = seapp_context_lookup(SEAPP_TYPE, info ? info->uid : uid, 0,
- info ? info->seinfo : seinfo, info ? info->name : pkgname, ctx);
- if (rc < 0)
- goto err;
-
- ctx_str = context_str(ctx);
- if (!ctx_str)
- goto err;
-
- if (!strcmp(ctx_str, orig_ctx_str))
- goto out;
-
- rc = security_check_context(ctx_str);
- if (rc < 0)
- goto err;
-
- freecon(*secontextp);
- *secontextp = strdup(ctx_str);
- if (!(*secontextp))
- goto err;
-
- rc = 0;
+ ctx = context_new(orig_ctx_str);
+ if (!ctx)
+ goto err;
+
+ rc = seapp_context_lookup(SEAPP_TYPE, info ? info->uid : uid, 0,
+ info ? info->seinfo : seinfo, info ? info->name : pkgname, ctx);
+ if (rc < 0)
+ goto err;
+
+ ctx_str = context_str(ctx);
+ if (!ctx_str)
+ goto err;
+
+ if (!strcmp(ctx_str, orig_ctx_str))
+ goto out;
+
+ rc = security_check_context(ctx_str);
+ if (rc < 0)
+ goto err;
+
+ freecon(*secontextp);
+ *secontextp = strdup(ctx_str);
+ if (!(*secontextp))
+ goto err;
+
+ rc = 0;
out:
- free(pkgname);
- context_free(ctx);
- return rc;
+ free(pkgname);
+ context_free(ctx);
+ return rc;
err:
- selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
- __FUNCTION__, pathname, pkgname, info ? info->seinfo : seinfo,
- info ? info->uid : uid, strerror(errno));
- rc = -1;
- goto out;
+ selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
+ __FUNCTION__, pathname, pkgname, info ? info->seinfo : seinfo,
+ info ? info->uid : uid, strerror(errno));
+ rc = -1;
+ goto out;
}
#define RESTORECON_PARTIAL_MATCH_DIGEST "security.sehash"
-static int restorecon_sb(const char *pathname, const struct stat *sb,
- bool nochange, bool verbose,
- const char *seinfo, uid_t uid)
+static int restorecon_sb(const char *pathname,
+ const struct stat *sb,
+ bool nochange,
+ bool verbose,
+ const char *seinfo,
+ uid_t uid)
{
- char *secontext = NULL;
- char *oldsecontext = NULL;
- int rc = 0;
-
- if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0)
- return 0; /* no match, but not an error */
-
- if (lgetfilecon(pathname, &oldsecontext) < 0)
- goto err;
-
- /*
- * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
- * and use pkgdir_selabel_lookup() instead. Files within those directories
- * have different labeling rules, based off of /seapp_contexts, and
- * installd is responsible for managing these labels instead of init.
- */
- if (is_app_data_path(pathname)) {
- if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
- goto err;
- }
-
- if (strcmp(oldsecontext, secontext) != 0) {
- if (verbose)
- selinux_log(SELINUX_INFO,
- "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
- if (!nochange) {
- if (lsetfilecon(pathname, secontext) < 0)
- goto err;
- }
- }
-
- rc = 0;
+ char *secontext = NULL;
+ char *oldsecontext = NULL;
+ int rc = 0;
+
+ if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0)
+ return 0; /* no match, but not an error */
+
+ if (lgetfilecon(pathname, &oldsecontext) < 0)
+ goto err;
+
+ /*
+ * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
+ * and use pkgdir_selabel_lookup() instead. Files within those directories
+ * have different labeling rules, based off of /seapp_contexts, and
+ * installd is responsible for managing these labels instead of init.
+ */
+ if (is_app_data_path(pathname)) {
+ if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
+ goto err;
+ }
+
+ if (strcmp(oldsecontext, secontext) != 0) {
+ if (verbose)
+ selinux_log(SELINUX_INFO,
+ "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
+ if (!nochange) {
+ if (lsetfilecon(pathname, secontext) < 0)
+ goto err;
+ }
+ }
+
+ rc = 0;
out:
- freecon(oldsecontext);
- freecon(secontext);
- return rc;
+ freecon(oldsecontext);
+ freecon(secontext);
+ return rc;
err:
- selinux_log(SELINUX_ERROR,
- "SELinux: Could not set context for %s: %s\n",
- pathname, strerror(errno));
- rc = -1;
- goto out;
+ selinux_log(SELINUX_ERROR,
+ "SELinux: Could not set context for %s: %s\n",
+ pathname, strerror(errno));
+ rc = -1;
+ goto out;
}
#define SYS_PATH "/sys"
#define SYS_PREFIX SYS_PATH "/"
struct dir_hash_node {
- char* path;
- uint8_t digest[SHA1_HASH_SIZE];
- struct dir_hash_node *next;
+ char* path;
+ uint8_t digest[SHA1_HASH_SIZE];
+ struct dir_hash_node *next;
};
// Returns true if the digest of all partial matched contexts is the same as the one
// saved by setxattr. Otherwise returns false and constructs a dir_hash_node with the
// newly calculated digest.
-static bool check_context_match_for_dir(const char *pathname, struct dir_hash_node **new_node,
- bool force, int error) {
- uint8_t read_digest[SHA1_HASH_SIZE];
- ssize_t read_size = getxattr(pathname, RESTORECON_PARTIAL_MATCH_DIGEST,
- read_digest, SHA1_HASH_SIZE);
- uint8_t calculated_digest[SHA1_HASH_SIZE];
- bool status = selabel_hash_all_partial_matches(fc_sehandle, pathname,
- calculated_digest);
-
- if (!new_node) {
- return false;
- }
- *new_node = NULL;
- if (!force && status && read_size == SHA1_HASH_SIZE &&
- memcmp(read_digest, calculated_digest, SHA1_HASH_SIZE) == 0) {
- return true;
- }
-
- // Save the digest of all matched contexts for the current directory.
- if (!error && status) {
- *new_node = calloc(1, sizeof(struct dir_hash_node));
- if (*new_node == NULL) {
- selinux_log(SELINUX_ERROR,
- "SELinux: %s: Out of memory\n", __func__);
- return false;
- }
-
- (*new_node)->path = strdup(pathname);
- if ((*new_node)->path == NULL) {
- selinux_log(SELINUX_ERROR,
- "SELinux: %s: Out of memory\n", __func__);
- free(*new_node);
- *new_node = NULL;
- return false;
- }
- memcpy((*new_node)->digest, calculated_digest, SHA1_HASH_SIZE);
- (*new_node)->next = NULL;
- }
-
- return false;
+static bool check_context_match_for_dir(const char *pathname,
+ struct dir_hash_node **new_node,
+ bool force, int error)
+{
+ uint8_t read_digest[SHA1_HASH_SIZE];
+ ssize_t read_size = getxattr(pathname, RESTORECON_PARTIAL_MATCH_DIGEST,
+ read_digest, SHA1_HASH_SIZE);
+ uint8_t calculated_digest[SHA1_HASH_SIZE];
+ bool status = selabel_hash_all_partial_matches(fc_sehandle, pathname,
+ calculated_digest);
+
+ if (!new_node) {
+ return false;
+ }
+ *new_node = NULL;
+ if (!force && status && read_size == SHA1_HASH_SIZE &&
+ memcmp(read_digest, calculated_digest, SHA1_HASH_SIZE) == 0) {
+ return true;
+ }
+
+ // Save the digest of all matched contexts for the current directory.
+ if (!error && status) {
+ *new_node = calloc(1, sizeof(struct dir_hash_node));
+ if (*new_node == NULL) {
+ selinux_log(SELINUX_ERROR,
+ "SELinux: %s: Out of memory\n", __func__);
+ return false;
+ }
+
+ (*new_node)->path = strdup(pathname);
+ if ((*new_node)->path == NULL) {
+ selinux_log(SELINUX_ERROR,
+ "SELinux: %s: Out of memory\n", __func__);
+ free(*new_node);
+ *new_node = NULL;
+ return false;
+ }
+ memcpy((*new_node)->digest, calculated_digest, SHA1_HASH_SIZE);
+ (*new_node)->next = NULL;
+ }
+
+ return false;
}
static int selinux_android_restorecon_common(const char* pathname_orig,
- const char *seinfo,
- uid_t uid,
- unsigned int flags)
+ const char *seinfo,
+ uid_t uid,
+ unsigned int flags)
{
- bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
- bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
- bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
- bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
- bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
- bool skipce = (flags & SELINUX_ANDROID_RESTORECON_SKIPCE) ? true : false;
- bool cross_filesystems = (flags & SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS) ? true : false;
- bool setrestoreconlast = (flags & SELINUX_ANDROID_RESTORECON_SKIP_SEHASH) ? false : true;
- bool issys;
- struct stat sb;
- struct statfs sfsb;
- FTS *fts;
- FTSENT *ftsent;
- char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
- char * paths[2] = { NULL , NULL };
- int ftsflags = FTS_NOCHDIR | FTS_PHYSICAL;
- int error, sverrno;
- struct dir_hash_node *current = NULL;
- struct dir_hash_node *head = NULL;
-
- if (!cross_filesystems) {
- ftsflags |= FTS_XDEV;
- }
-
- if (is_selinux_enabled() <= 0) {
- selinux_log(SELINUX_WARNING, "SELinux: SELinux is disabled, skipping restorecon");
- return 0;
- }
-
- __selinux_once(fc_once, file_context_init);
-
- if (!fc_sehandle)
- return 0;
-
- /*
- * Convert passed-in pathname to canonical pathname by resolving realpath of
- * containing dir, then appending last component name.
- */
- pathbname = basename(pathname_orig);
- if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || !strcmp(pathbname, "..")) {
- pathname = realpath(pathname_orig, NULL);
- if (!pathname)
- goto realpatherr;
- } else {
- pathdname = dirname(pathname_orig);
- pathdnamer = realpath(pathdname, NULL);
- if (!pathdnamer)
- goto realpatherr;
- if (!strcmp(pathdnamer, "/"))
- error = asprintf(&pathname, "/%s", pathbname);
- else
- error = asprintf(&pathname, "%s/%s", pathdnamer, pathbname);
- if (error < 0)
- goto oom;
- }
-
- paths[0] = pathname;
- issys = (!strcmp(pathname, SYS_PATH)
- || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false;
-
- if (!recurse) {
- if (lstat(pathname, &sb) < 0) {
- error = -1;
- goto cleanup;
- }
-
- error = restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
- goto cleanup;
- }
-
- /*
- * Ignore saved partial match digest on /data/data or /data/user
- * since their labeling is based on seapp_contexts and seinfo
- * assignments rather than file_contexts and is managed by
- * installd rather than init.
- */
- if (is_app_data_path(pathname))
- setrestoreconlast = false;
-
- /* Also ignore on /sys since it is regenerated on each boot regardless. */
- if (issys)
- setrestoreconlast = false;
-
- /* Ignore files on in-memory filesystems */
- if (statfs(pathname, &sfsb) == 0) {
- if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC)
- setrestoreconlast = false;
- }
-
- fts = fts_open(paths, ftsflags, NULL);
- if (!fts) {
- error = -1;
- goto cleanup;
- }
-
- error = 0;
- while ((ftsent = fts_read(fts)) != NULL) {
- switch (ftsent->fts_info) {
- case FTS_DC:
- selinux_log(SELINUX_ERROR,
- "SELinux: Directory cycle on %s.\n", ftsent->fts_path);
- errno = ELOOP;
- error = -1;
- goto out;
- case FTS_DP:
- continue;
- case FTS_DNR:
- selinux_log(SELINUX_ERROR,
- "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- case FTS_NS:
- selinux_log(SELINUX_ERROR,
- "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- case FTS_ERR:
- selinux_log(SELINUX_ERROR,
- "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- case FTS_D:
- if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) {
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- }
-
- if (!datadata && !fnmatch(USER_PROFILE_PATH, ftsent->fts_path, FNM_PATHNAME)) {
- // Don't label this directory, vold takes care of that, but continue below it.
- continue;
- }
-
- if (setrestoreconlast) {
- struct dir_hash_node* new_node = NULL;
- if (check_context_match_for_dir(ftsent->fts_path, &new_node, force, error)) {
- selinux_log(SELINUX_INFO,
- "SELinux: Skipping restorecon on directory(%s)\n",
- ftsent->fts_path);
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- }
- if (new_node) {
- if (!current) {
- current = new_node;
- head = current;
- } else {
- current->next = new_node;
- current = current->next;
- }
- }
- }
-
- if (skipce &&
- (!strncmp(ftsent->fts_path, DATA_SYSTEM_CE_PATH, sizeof(DATA_SYSTEM_CE_PATH)-1) ||
- !strncmp(ftsent->fts_path, DATA_MISC_CE_PATH, sizeof(DATA_MISC_CE_PATH)-1) ||
- !strncmp(ftsent->fts_path, DATA_VENDOR_CE_PATH, sizeof(DATA_VENDOR_CE_PATH)-1))) {
- // Don't label anything below this directory.
- fts_set(fts, ftsent, FTS_SKIP);
- // but fall through and make sure we label the directory itself
- }
-
- if (!datadata && is_app_data_path(ftsent->fts_path)) {
- // Don't label anything below this directory.
- fts_set(fts, ftsent, FTS_SKIP);
- // but fall through and make sure we label the directory itself
- }
- /* fall through */
- default:
- error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
- break;
- }
- }
-
- // Labeling successful. Write the partial match digests for subdirectories.
- // TODO: Write the digest upon FTS_DP if no error occurs in its descents.
- if (setrestoreconlast && !nochange && !error) {
- current = head;
- while (current != NULL) {
- if (setxattr(current->path, RESTORECON_PARTIAL_MATCH_DIGEST, current->digest,
- SHA1_HASH_SIZE, 0) < 0) {
- selinux_log(SELINUX_ERROR,
- "SELinux: setxattr failed: %s: %s\n",
- current->path,
- strerror(errno));
- }
- current = current->next;
- }
- }
+ bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
+ bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
+ bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
+ bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
+ bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
+ bool skipce = (flags & SELINUX_ANDROID_RESTORECON_SKIPCE) ? true : false;
+ bool cross_filesystems = (flags & SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS) ? true : false;
+ bool setrestoreconlast = (flags & SELINUX_ANDROID_RESTORECON_SKIP_SEHASH) ? false : true;
+ bool issys;
+ struct stat sb;
+ struct statfs sfsb;
+ FTS *fts;
+ FTSENT *ftsent;
+ char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
+ char * paths[2] = { NULL , NULL };
+ int ftsflags = FTS_NOCHDIR | FTS_PHYSICAL;
+ int error, sverrno;
+ struct dir_hash_node *current = NULL;
+ struct dir_hash_node *head = NULL;
+
+ if (!cross_filesystems) {
+ ftsflags |= FTS_XDEV;
+ }
+
+ if (is_selinux_enabled() <= 0) {
+ selinux_log(SELINUX_WARNING, "SELinux: SELinux is disabled, skipping restorecon");
+ return 0;
+ }
+
+ __selinux_once(fc_once, file_context_init);
+
+ if (!fc_sehandle)
+ return 0;
+
+ /*
+ * Convert passed-in pathname to canonical pathname by resolving realpath of
+ * containing dir, then appending last component name.
+ */
+ pathbname = basename(pathname_orig);
+ if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || !strcmp(pathbname, "..")) {
+ pathname = realpath(pathname_orig, NULL);
+ if (!pathname)
+ goto realpatherr;
+ } else {
+ pathdname = dirname(pathname_orig);
+ pathdnamer = realpath(pathdname, NULL);
+ if (!pathdnamer)
+ goto realpatherr;
+ if (!strcmp(pathdnamer, "/"))
+ error = asprintf(&pathname, "/%s", pathbname);
+ else
+ error = asprintf(&pathname, "%s/%s", pathdnamer, pathbname);
+ if (error < 0)
+ goto oom;
+ }
+
+ paths[0] = pathname;
+ issys = (!strcmp(pathname, SYS_PATH)
+ || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false;
+
+ if (!recurse) {
+ if (lstat(pathname, &sb) < 0) {
+ error = -1;
+ goto cleanup;
+ }
+
+ error = restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
+ goto cleanup;
+ }
+
+ /*
+ * Ignore saved partial match digest on /data/data or /data/user
+ * since their labeling is based on seapp_contexts and seinfo
+ * assignments rather than file_contexts and is managed by
+ * installd rather than init.
+ */
+ if (is_app_data_path(pathname))
+ setrestoreconlast = false;
+
+ /* Also ignore on /sys since it is regenerated on each boot regardless. */
+ if (issys)
+ setrestoreconlast = false;
+
+ /* Ignore files on in-memory filesystems */
+ if (statfs(pathname, &sfsb) == 0) {
+ if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC)
+ setrestoreconlast = false;
+ }
+
+ fts = fts_open(paths, ftsflags, NULL);
+ if (!fts) {
+ error = -1;
+ goto cleanup;
+ }
+
+ error = 0;
+ while ((ftsent = fts_read(fts)) != NULL) {
+ switch (ftsent->fts_info) {
+ case FTS_DC:
+ selinux_log(SELINUX_ERROR,
+ "SELinux: Directory cycle on %s.\n", ftsent->fts_path);
+ errno = ELOOP;
+ error = -1;
+ goto out;
+ case FTS_DP:
+ continue;
+ case FTS_DNR:
+ selinux_log(SELINUX_ERROR,
+ "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_NS:
+ selinux_log(SELINUX_ERROR,
+ "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_ERR:
+ selinux_log(SELINUX_ERROR,
+ "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_D:
+ if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) {
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ }
+
+ if (!datadata && !fnmatch(USER_PROFILE_PATH, ftsent->fts_path, FNM_PATHNAME)) {
+ // Don't label this directory, vold takes care of that, but continue below it.
+ continue;
+ }
+
+ if (setrestoreconlast) {
+ struct dir_hash_node* new_node = NULL;
+ if (check_context_match_for_dir(ftsent->fts_path, &new_node, force, error)) {
+ selinux_log(SELINUX_INFO,
+ "SELinux: Skipping restorecon on directory(%s)\n",
+ ftsent->fts_path);
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ }
+ if (new_node) {
+ if (!current) {
+ current = new_node;
+ head = current;
+ } else {
+ current->next = new_node;
+ current = current->next;
+ }
+ }
+ }
+
+ if (skipce && is_credential_encrypted_path(ftsent->fts_path)) {
+ // Don't label anything below this directory.
+ fts_set(fts, ftsent, FTS_SKIP);
+ // but fall through and make sure we label the directory itself
+ }
+
+ if (!datadata && is_app_data_path(ftsent->fts_path)) {
+ // Don't label anything below this directory.
+ fts_set(fts, ftsent, FTS_SKIP);
+ // but fall through and make sure we label the directory itself
+ }
+ /* fall through */
+ default:
+ error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
+ break;
+ }
+ }
+
+ // Labeling successful. Write the partial match digests for subdirectories.
+ // TODO: Write the digest upon FTS_DP if no error occurs in its descents.
+ if (setrestoreconlast && !nochange && !error) {
+ current = head;
+ while (current != NULL) {
+ if (setxattr(current->path, RESTORECON_PARTIAL_MATCH_DIGEST, current->digest,
+ SHA1_HASH_SIZE, 0) < 0) {
+ selinux_log(SELINUX_ERROR,
+ "SELinux: setxattr failed: %s: %s\n",
+ current->path,
+ strerror(errno));
+ }
+ current = current->next;
+ }
+ }
out:
- sverrno = errno;
- (void) fts_close(fts);
- errno = sverrno;
+ sverrno = errno;
+ (void) fts_close(fts);
+ errno = sverrno;
cleanup:
- free(pathdnamer);
- free(pathname);
- current = head;
- while (current != NULL) {
- struct dir_hash_node *next = current->next;
- free(current->path);
- free(current);
- current = next;
- }
- return error;
+ free(pathdnamer);
+ free(pathname);
+ current = head;
+ while (current != NULL) {
+ struct dir_hash_node *next = current->next;
+ free(current->path);
+ free(current);
+ current = next;
+ }
+ return error;
oom:
- sverrno = errno;
- selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
- errno = sverrno;
- error = -1;
- goto cleanup;
+ sverrno = errno;
+ selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
+ errno = sverrno;
+ error = -1;
+ goto cleanup;
realpatherr:
- sverrno = errno;
- selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %s.\n",
- pathname_orig, strerror(errno));
- errno = sverrno;
- error = -1;
- goto cleanup;
+ sverrno = errno;
+ selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %s.\n",
+ pathname_orig, strerror(errno));
+ errno = sverrno;
+ error = -1;
+ goto cleanup;
}
int selinux_android_restorecon(const char *file, unsigned int flags)
{
- return selinux_android_restorecon_common(file, NULL, -1, flags);
+ return selinux_android_restorecon_common(file, NULL, -1, flags);
}
int selinux_android_restorecon_pkgdir(const char *pkgdir,
- const char *seinfo,
- uid_t uid,
- unsigned int flags)
+ const char *seinfo,
+ uid_t uid,
+ unsigned int flags)
{
- return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
+ return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
}
void selinux_android_set_sehandle(const struct selabel_handle *hndl)
{
- fc_sehandle = (struct selabel_handle *) hndl;
+ fc_sehandle = (struct selabel_handle *) hndl;
}
int selinux_android_load_policy()
diff --git a/libselinux/src/android/android_internal.h b/libselinux/src/android/android_internal.h
index e5d69402..ada11078 100644
--- a/libselinux/src/android/android_internal.h
+++ b/libselinux/src/android/android_internal.h
@@ -55,6 +55,27 @@ struct selabel_handle* context_handle(
const path_alts_t *context_paths,
const char* name);
+/*
+ * This method helps in identifying paths that refer to users' app data.
+ * Labeling for app data is based on seapp_contexts and seinfo assignments
+ * rather than file_contexts and is managed by installd rather than by init.
+ */
+bool is_app_data_path(const char *pathname);
+
+/*
+ * Determines if a path is Credential Encrypted (CE).
+ * Some paths are not available when the device first boots (these are protected
+ * by a credential). They should not be processed by restorecon until decrypted.
+ * See also the --skip-ce option for restorecon.
+ */
+bool is_credential_encrypted_path(const char *pathname);
+
+/* Extract the pkgname and userid from a path.
+ * On success, the caller is responsible for free'ing pkgname.
+ * Returns 0 on success, -1 on invalid path, -2 on error.
+ */
+int extract_pkgname_and_userid(const char *pathname, char **pkgname, unsigned int *userid);
+
/* The kind of request when looking up an seapp_context. */
enum seapp_kind {
/* Returns the SELinux type for the app data directory */
diff --git a/libselinux/src/android/android_unittest.cpp b/libselinux/src/android/android_unittest.cpp
index 1eb9056e..28a75247 100644
--- a/libselinux/src/android/android_unittest.cpp
+++ b/libselinux/src/android/android_unittest.cpp
@@ -172,3 +172,61 @@ TEST(AndroidSeAppTest, ParseOverflow)
ret = parse_seinfo(seinfo.c_str(), &info);
EXPECT_EQ(ret, -1);
}
+
+TEST(AndroidSELinuxPathTest, IsAppDataPath)
+{
+ EXPECT_TRUE(is_app_data_path("/data/data"));
+ EXPECT_TRUE(is_app_data_path("/data/user/0"));
+
+ EXPECT_FALSE(is_app_data_path("/data"));
+}
+
+TEST(AndroidSELinuxPathTest, IsCredentialEncryptedPath)
+{
+ EXPECT_TRUE(is_credential_encrypted_path("/data/system_ce/0"));
+ EXPECT_TRUE(is_credential_encrypted_path("/data/system_ce/0/backup"));
+ EXPECT_TRUE(is_credential_encrypted_path("/data/misc_ce/0"));
+ EXPECT_TRUE(is_credential_encrypted_path("/data/misc_ce/0/apexdata"));
+ EXPECT_TRUE(is_credential_encrypted_path("/data/vendor_ce/0"));
+ EXPECT_TRUE(is_credential_encrypted_path("/data/vendor_ce/0/data"));
+
+ EXPECT_FALSE(is_credential_encrypted_path("/data"));
+ EXPECT_FALSE(is_credential_encrypted_path("/data/data"));
+ EXPECT_FALSE(is_credential_encrypted_path("/data/user/0"));
+}
+
+TEST(AndroidSELinuxPathTest, ExtractPkgnameAndUserid)
+{
+ char *pkgname = NULL;
+ unsigned int userid;
+
+ EXPECT_EQ(extract_pkgname_and_userid("/data/", &pkgname, &userid), -1);
+
+ char const* path = "/data/user/0/com.android.myapp";
+ EXPECT_EQ(extract_pkgname_and_userid(path, &pkgname, &userid), 0);
+ EXPECT_STREQ("com.android.myapp", pkgname);
+ EXPECT_EQ(userid, 0);
+ free(pkgname);
+ pkgname = NULL;
+
+ path = "/data/user/0/com.android.myapp/som/subdir";
+ EXPECT_EQ(extract_pkgname_and_userid(path, &pkgname, &userid), 0);
+ EXPECT_STREQ("com.android.myapp", pkgname);
+ EXPECT_EQ(userid, 0);
+ free(pkgname);
+ pkgname = NULL;
+
+ path = "/data/data/com.android.myapp2";
+ EXPECT_EQ(extract_pkgname_and_userid(path, &pkgname, &userid), 0);
+ EXPECT_STREQ("com.android.myapp2", pkgname);
+ EXPECT_EQ(userid, 0);
+ free(pkgname);
+ pkgname = NULL;
+
+ path = "/data/misc_de/10/sdksandbox/com.android.myapp3";
+ EXPECT_EQ(extract_pkgname_and_userid(path, &pkgname, &userid), 0);
+ EXPECT_STREQ("com.android.myapp3", pkgname);
+ EXPECT_EQ(userid, 10);
+ free(pkgname);
+ pkgname = NULL;
+}