[PATCH] Revert "libselinux: restorecon: pin file to avoid TOCTOU issues"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This reverts commit 7e979b56fd2cee28f647376a7233d2ac2d12ca50.

The reverted commit broke `setfiles` when it's run from a chroot
without /proc mounted, e.g.

    # chroot /mnt/sysimage

    chroot# setfiles -e /proc -e /sys /sys /etc/selinux/targeted/contexts/files/file_contexts /
    [strace]
    openat(AT_FDCWD, "/", O_RDONLY|O_EXCL|O_NOFOLLOW|O_PATH) = 3
    newfstatat(3, "", {st_mode=S_IFDIR|0555, st_size=4096, ...}, AT_EMPTY_PATH) = 0
    mmap(NULL, 2101248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1697c91000
    fgetxattr(3, "security.selinux", 0x55be8881d3f0, 255) = -1 EBADF (Bad file descriptor)
    fcntl(3, F_GETFL)                       = 0x220000 (flags O_RDONLY|O_NOFOLLOW|O_PATH)
    getxattr("/proc/self/fd/3", "security.selinux", 0x55be8881d3f0, 255) = -1 ENOENT (No such file or directory)
    [/strace]
    setfiles: Could not set context for /:  No such file or directory

Signed-off-by: Petr Lautrbach <plautrba@xxxxxxxxxx>
---
 libselinux/src/selinux_restorecon.c | 43 ++++++++++++-----------------
 1 file changed, 18 insertions(+), 25 deletions(-)

diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index 9dd6be817832..9f5b326c19ec 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -623,13 +623,13 @@ out:
 	return rc;
 }
 
-static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first)
+static int restorecon_sb(const char *pathname, const struct stat *sb,
+			    struct rest_flags *flags, bool first)
 {
 	char *newcon = NULL;
 	char *curcon = NULL;
 	char *newtypecon = NULL;
-	int fd = -1, rc;
-	struct stat stat_buf;
+	int rc;
 	bool updated = false;
 	const char *lookup_path = pathname;
 	float pc;
@@ -644,21 +644,13 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
 		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, "/",
-						    stat_buf.st_mode);
+						    sb->st_mode);
 	else
 		rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path,
-						    stat_buf.st_mode);
+						    sb->st_mode);
 
 	if (rc < 0) {
 		if (errno == ENOENT) {
@@ -667,10 +659,10 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
 					    "Warning no default label for %s\n",
 					    lookup_path);
 
-			goto out; /* no match, but not an error */
+			return 0; /* no match, but not an error */
 		}
 
-		goto err;
+		return -1;
 	}
 
 	if (flags->progress) {
@@ -690,17 +682,19 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
 	}
 
 	if (flags->add_assoc) {
-		rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags);
+		rc = filespec_add(sb->st_ino, newcon, pathname, flags);
 
 		if (rc < 0) {
 			selinux_log(SELINUX_ERROR,
 				    "filespec_add error: %s\n", pathname);
-			goto out1;
+			freecon(newcon);
+			return -1;
 		}
 
 		if (rc > 0) {
 			/* Already an association and it took precedence. */
-			goto out;
+			freecon(newcon);
+			return 0;
 		}
 	}
 
@@ -708,7 +702,7 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
 		selinux_log(SELINUX_INFO, "%s matched by %s\n",
 			    pathname, newcon);
 
-	if (fgetfilecon_raw(fd, &curcon) < 0) {
+	if (lgetfilecon_raw(pathname, &curcon) < 0) {
 		if (errno != ENODATA)
 			goto err;
 
@@ -741,7 +735,7 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
 		}
 
 		if (!flags->nochange) {
-			if (fsetfilecon(fd, newcon) < 0)
+			if (lsetfilecon(pathname, newcon) < 0)
 				goto err;
 			updated = true;
 		}
@@ -766,8 +760,6 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
 out:
 	rc = 0;
 out1:
-	if (fd >= 0)
-		close(fd);
 	freecon(curcon);
 	freecon(newcon);
 	return rc;
@@ -865,6 +857,7 @@ 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)
@@ -962,11 +955,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, &state->flags,
+			error = restorecon_sb(ent_path, &ent_st, &state->flags,
 					      first);
 
 			if (state->parallel) {
@@ -1162,7 +1155,7 @@ static int selinux_restorecon_common(const char *pathname_orig,
 			goto cleanup;
 		}
 
-		error = restorecon_sb(pathname, &state.flags, true);
+		error = restorecon_sb(pathname, &sb, &state.flags, true);
 		goto cleanup;
 	}
 
-- 
2.36.1




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux