aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTianjie Xu <xunchang@google.com>2019-03-05 17:06:13 -0800
committerandroid-build-merger <android-build-merger@google.com>2019-03-05 17:06:13 -0800
commit490f24b110663defdc12d623a17f77e2ae087321 (patch)
tree28b59b7bea61734e325de2c7323ed167d2f1b59b
parent37d9a7033f37348bf47b11ace05d4c2a17d69908 (diff)
parentd2914865822c5eabd42d0fc71294b117b42a7dfd (diff)
downloadandroid_external_selinux-490f24b110663defdc12d623a17f77e2ae087321.tar.gz
android_external_selinux-490f24b110663defdc12d623a17f77e2ae087321.tar.bz2
android_external_selinux-490f24b110663defdc12d623a17f77e2ae087321.zip
Merge "Restorecon: save digest of all partial matches for directory" am: f797b5b327 am: 63b151c687
am: d291486582 Change-Id: Ib01e2bd0e917790290191a1e4bf8480fcf93bb75
-rw-r--r--libselinux/src/android/android_platform.c113
1 files changed, 95 insertions, 18 deletions
diff --git a/libselinux/src/android/android_platform.c b/libselinux/src/android/android_platform.c
index 56e2cc5f..7b39b793 100644
--- a/libselinux/src/android/android_platform.c
+++ b/libselinux/src/android/android_platform.c
@@ -1443,7 +1443,7 @@ err:
goto out;
}
-#define RESTORECON_LAST "security.restorecon_last"
+#define RESTORECON_PARTIAL_MATCH_DIGEST "security.sehash"
static int restorecon_sb(const char *pathname, const struct stat *sb,
bool nochange, bool verbose,
@@ -1502,6 +1502,57 @@ err:
#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;
+};
+
+// 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 int selinux_android_restorecon_common(const char* pathname_orig,
const char *seinfo,
uid_t uid,
@@ -1524,8 +1575,8 @@ static int selinux_android_restorecon_common(const char* pathname_orig,
char * paths[2] = { NULL , NULL };
int ftsflags = FTS_NOCHDIR | FTS_PHYSICAL;
int error, sverrno;
- char xattr_value[FC_DIGEST_SIZE];
- ssize_t size;
+ struct dir_hash_node *current = NULL;
+ struct dir_hash_node *head = NULL;
if (!cross_filesystems) {
ftsflags |= FTS_XDEV;
@@ -1576,7 +1627,7 @@ static int selinux_android_restorecon_common(const char* pathname_orig,
}
/*
- * Ignore restorecon_last on /data/data or /data/user
+ * 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.
@@ -1598,17 +1649,6 @@ static int selinux_android_restorecon_common(const char* pathname_orig,
setrestoreconlast = false;
}
- if (setrestoreconlast) {
- size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
- if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
- selinux_log(SELINUX_INFO,
- "SELinux: Skipping restorecon_recursive(%s)\n",
- pathname);
- error = 0;
- goto cleanup;
- }
- }
-
fts = fts_open(paths, ftsflags, NULL);
if (!fts) {
error = -1;
@@ -1647,6 +1687,26 @@ static int selinux_android_restorecon_common(const char* pathname_orig,
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_PREFIX, sizeof(DATA_SYSTEM_CE_PREFIX)-1) ||
!strncmp(ftsent->fts_path, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1))) {
@@ -1672,10 +1732,20 @@ static int selinux_android_restorecon_common(const char* pathname_orig,
}
}
- // Labeling successful. Mark the top level directory as completed.
+ // 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) {
- if (setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0) < 0)
- selinux_log(SELINUX_ERROR, "SELinux: setxattr failed: %s: %s\n", pathname, strerror(errno));
+ 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:
@@ -1685,6 +1755,13 @@ out:
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;
oom:
sverrno = errno;