mirror of
https://github.com/topjohnwu/selinux.git
synced 2024-12-14 23:18:38 +00:00
e016502c0a
We used to hash the file_context and skip the restorecon on the top level directory if the hash doesn't change. But the file_context might change after an OTA update; and some users experienced long restorecon time as they have lots of files under directories like /data/media. This CL tries to hash all the partial match entries in the file_context for each directory; and skips the restorecon if that digest stays the same, regardless of the changes to the other parts of file_context. This is a version ported from Android that was originally written by: xunchang <xunchang@google.com> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
171 lines
3.8 KiB
C
171 lines
3.8 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <fts.h>
|
|
#include <selinux/selinux.h>
|
|
#include <selinux/label.h>
|
|
|
|
#include "../src/label_file.h"
|
|
|
|
static __attribute__ ((__noreturn__)) void usage(const char *progname)
|
|
{
|
|
fprintf(stderr,
|
|
"usage: %s [-vr] [-f file] path\n\n"
|
|
"Where:\n\t"
|
|
"-v Validate file_contxts entries against loaded policy.\n\t"
|
|
"-r Recursively descend directories.\n\t"
|
|
"-f Optional file_contexts file (defaults to current policy).\n\t"
|
|
"path Path to check current SHA1 digest against file_contexts entries.\n\n"
|
|
"This will check the directory selinux.sehash SHA1 digest for "
|
|
"<path> against\na newly generated digest based on the "
|
|
"file_context entries for that node\n(using the regx, mode "
|
|
"and path entries).\n", progname);
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int opt, fts_flags;
|
|
size_t i, digest_len;
|
|
bool status, recurse = false;
|
|
FTS *fts;
|
|
FTSENT *ftsent;
|
|
char *validate = NULL, *file = NULL;
|
|
char *paths[2] = { NULL, NULL };
|
|
uint8_t *xattr_digest = NULL;
|
|
uint8_t *calculated_digest = NULL;
|
|
char *sha1_buf = NULL;
|
|
|
|
struct selabel_handle *hnd;
|
|
struct selinux_opt selabel_option[] = {
|
|
{ SELABEL_OPT_PATH, file },
|
|
{ SELABEL_OPT_VALIDATE, validate }
|
|
};
|
|
|
|
if (argc < 2)
|
|
usage(argv[0]);
|
|
|
|
while ((opt = getopt(argc, argv, "f:rv")) > 0) {
|
|
switch (opt) {
|
|
case 'f':
|
|
file = optarg;
|
|
break;
|
|
case 'r':
|
|
recurse = true;
|
|
break;
|
|
case 'v':
|
|
validate = (char *)1;
|
|
break;
|
|
default:
|
|
usage(argv[0]);
|
|
}
|
|
}
|
|
|
|
if (optind >= argc) {
|
|
fprintf(stderr, "No pathname specified\n");
|
|
exit(-1);
|
|
}
|
|
|
|
paths[0] = argv[optind];
|
|
|
|
selabel_option[0].value = file;
|
|
selabel_option[1].value = validate;
|
|
|
|
hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2);
|
|
if (!hnd) {
|
|
fprintf(stderr, "ERROR: selabel_open - Could not obtain "
|
|
"handle.\n");
|
|
return -1;
|
|
}
|
|
|
|
fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
|
|
fts = fts_open(paths, fts_flags, NULL);
|
|
if (!fts) {
|
|
printf("fts error on %s: %s\n",
|
|
paths[0], strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
while ((ftsent = fts_read(fts)) != NULL) {
|
|
switch (ftsent->fts_info) {
|
|
case FTS_DP:
|
|
continue;
|
|
case FTS_D: {
|
|
|
|
xattr_digest = NULL;
|
|
calculated_digest = NULL;
|
|
digest_len = 0;
|
|
|
|
status = selabel_get_digests_all_partial_matches(hnd,
|
|
ftsent->fts_path,
|
|
&calculated_digest,
|
|
&xattr_digest,
|
|
&digest_len);
|
|
|
|
sha1_buf = calloc(1, digest_len * 2 + 1);
|
|
if (!sha1_buf) {
|
|
fprintf(stderr, "Could not calloc buffer ERROR: %s\n",
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (status) { /* They match */
|
|
printf("xattr and file_contexts SHA1 digests match for: %s\n",
|
|
ftsent->fts_path);
|
|
|
|
if (calculated_digest) {
|
|
for (i = 0; i < digest_len; i++)
|
|
sprintf((&sha1_buf[i * 2]),
|
|
"%02x",
|
|
calculated_digest[i]);
|
|
printf("SHA1 digest: %s\n", sha1_buf);
|
|
}
|
|
} else {
|
|
if (!calculated_digest) {
|
|
printf("No SHA1 digest available for: %s\n",
|
|
ftsent->fts_path);
|
|
printf("as file_context entry is \"<<none>>\"\n");
|
|
break;
|
|
}
|
|
|
|
printf("The file_context entries for: %s\n",
|
|
ftsent->fts_path);
|
|
|
|
for (i = 0; i < digest_len; i++)
|
|
sprintf((&sha1_buf[i * 2]), "%02x",
|
|
calculated_digest[i]);
|
|
printf("generated SHA1 digest: %s\n", sha1_buf);
|
|
|
|
if (!xattr_digest) {
|
|
printf("however there is no selinux.sehash xattr entry.\n");
|
|
} else {
|
|
printf("however it does NOT match the current entry of:\n");
|
|
for (i = 0; i < digest_len; i++)
|
|
sprintf((&sha1_buf[i * 2]),
|
|
"%02x",
|
|
xattr_digest[i]);
|
|
printf("%s\n", sha1_buf);
|
|
}
|
|
|
|
free(xattr_digest);
|
|
free(calculated_digest);
|
|
free(sha1_buf);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!recurse)
|
|
break;
|
|
}
|
|
|
|
(void) fts_close(fts);
|
|
(void) selabel_close(hnd);
|
|
return 0;
|
|
}
|