diff options
author | Tianjie Xu <xunchang@google.com> | 2019-03-05 17:06:13 -0800 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-03-05 17:06:13 -0800 |
commit | 490f24b110663defdc12d623a17f77e2ae087321 (patch) | |
tree | 28b59b7bea61734e325de2c7323ed167d2f1b59b | |
parent | 37d9a7033f37348bf47b11ace05d4c2a17d69908 (diff) | |
parent | d2914865822c5eabd42d0fc71294b117b42a7dfd (diff) | |
download | android_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.c | 113 |
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; |