diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index 42ef30cb..12b85101 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -621,13 +621,13 @@ out: return rc; } -static int restorecon_sb(const char *pathname, const struct stat *sb, - struct rest_flags *flags, bool first) +static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first) { char *newcon = NULL; char *curcon = NULL; char *newtypecon = NULL; - int rc; + int fd = -1, rc; + struct stat stat_buf; bool updated = false; const char *lookup_path = pathname; float pc; @@ -642,13 +642,21 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, lookup_path += rootpathlen; } + fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL); + if (fd < 0) + goto err; + + rc = fstat(fd, &stat_buf); + if (rc < 0) + goto err; + if (rootpath != NULL && lookup_path[0] == '\0') /* this is actually the root dir of the alt root. */ rc = selabel_lookup_raw(fc_sehandle, &newcon, "/", - sb->st_mode); + stat_buf.st_mode); else rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path, - sb->st_mode); + stat_buf.st_mode); if (rc < 0) { if (errno == ENOENT) { @@ -657,10 +665,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, "Warning no default label for %s\n", lookup_path); - return 0; /* no match, but not an error */ + goto out; /* no match, but not an error */ } - return -1; + goto err; } if (flags->progress) { @@ -680,19 +688,17 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } if (flags->add_assoc) { - rc = filespec_add(sb->st_ino, newcon, pathname, flags); + rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags); if (rc < 0) { selinux_log(SELINUX_ERROR, "filespec_add error: %s\n", pathname); - freecon(newcon); - return -1; + goto out1; } if (rc > 0) { /* Already an association and it took precedence. */ - freecon(newcon); - return 0; + goto out; } } @@ -700,7 +706,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, selinux_log(SELINUX_INFO, "%s matched by %s\n", pathname, newcon); - if (lgetfilecon_raw(pathname, &curcon) < 0) { + if (fgetfilecon_raw(fd, &curcon) < 0) { if (errno != ENODATA) goto err; @@ -733,7 +739,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } if (!flags->nochange) { - if (lsetfilecon(pathname, newcon) < 0) + if (fsetfilecon(fd, newcon) < 0) goto err; updated = true; } @@ -758,6 +764,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, out: rc = 0; out1: + if (fd >= 0) + close(fd); freecon(curcon); freecon(newcon); return rc; @@ -855,7 +863,6 @@ static void *selinux_restorecon_thread(void *arg) FTSENT *ftsent; int error; char ent_path[PATH_MAX]; - struct stat ent_st; bool first = false; if (state->parallel) @@ -953,11 +960,11 @@ loop_body: /* fall through */ default: strcpy(ent_path, ftsent->fts_path); - ent_st = *ftsent->fts_statp; + if (state->parallel) pthread_mutex_unlock(&state->mutex); - error = restorecon_sb(ent_path, &ent_st, &state->flags, + error = restorecon_sb(ent_path, &state->flags, first); if (state->parallel) { @@ -1153,7 +1160,7 @@ static int selinux_restorecon_common(const char *pathname_orig, goto cleanup; } - error = restorecon_sb(pathname, &sb, &state.flags, true); + error = restorecon_sb(pathname, &state.flags, true); goto cleanup; }