[PATCH 04/96] libselinux: resolv symlinks and dot directories before

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

 



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


This patch looks good to me. acked.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk5D47MACgkQrlYvE4MpobP/ugCeNi6CLFdWmXpMvqun3/xxzqgV
40cAn25ZrLkdtU5dwL1QxoJWIkpQrVPz
=JDBY
-----END PGP SIGNATURE-----
>From 5655a62d229005427d491e118af4fa6ce1980ecc Mon Sep 17 00:00:00 2001
From: Eric Paris <eparis@xxxxxxxxxx>
Date: Wed, 29 Jun 2011 00:11:17 -0400
Subject: [PATCH 04/96] libselinux: resolv symlinks and dot directories before
 matching paths

matchpathcon cannot handle ./ or ../ in pathnames and doesn't do well
with symlinks.  This patch uses the glibc function realpath() to try to
determine a real path with resolved symlinks and dot directories.  For
example before this pach we would see:

$ matchpathcon /tmp/../eric
/tmp/../eric	<<none>>
$ matchpathcon /eric
/eric	system_u:object_r:default_t:s0

Whereas after the path we get the same results.  The one quirk with the
patch is that we need special code to make sure that realpath() does not
follow a symlink if it is the final component.  aka if we have a symlink
from /eric to /tmp/eric we do not want to resolv to /tmp/eric.  We want
to just resolv to the actual symlink /eric.

Signed-off-by: Eric Paris <eparis@xxxxxxxxxx>
---
 libselinux/utils/matchpathcon.c |  107 ++++++++++++++++++++++++++++++++------
 1 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/libselinux/utils/matchpathcon.c b/libselinux/utils/matchpathcon.c
index 3d9f517..6bd86d0 100644
--- a/libselinux/utils/matchpathcon.c
+++ b/libselinux/utils/matchpathcon.c
@@ -4,10 +4,14 @@
 #include <getopt.h>
 #include <errno.h>
 #include <string.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/errno.h>
 #include <selinux/selinux.h>
+#include <limits.h>
+#include <stdlib.h>
+
 
 void usage(const char *progname)
 {
@@ -39,6 +43,63 @@ int printmatchpathcon(char *path, int header, int mode)
 	return 0;
 }
 
+/*
+ * We do not want to resolve a symlink to a real path if it is the final
+ * component of the name.  Thus we split the pathname on the last "/" and
+ * determine a real path component of the first portion.  We then have to
+ * copy the last part back on to get the final real path.  Wheww.
+ */
+static int symlink_realpath(char *name, char *resolved_path)
+{
+	char *last_component;
+	char *tmp_path, *p;
+	size_t len = 0;
+	int rc = 0;
+
+	tmp_path = strdup(name);
+	if (!tmp_path) {
+		fprintf(stderr, "symlink_realpath(%s) strdup() failed: %s\n",
+			name, strerror(errno));
+		rc = -1;
+		goto out;
+	}
+
+	last_component = strrchr(tmp_path, '/');
+
+	if (last_component == tmp_path) {
+		last_component++;
+		p = strcpy(resolved_path, "/");
+	} else if (last_component) {
+		*last_component = '\0';
+		last_component++;
+		p = realpath(tmp_path, resolved_path);
+	} else {
+		last_component = tmp_path;
+		p = realpath("./", resolved_path);
+	}
+
+	if (!p) {
+		fprintf(stderr, "symlink_realpath(%s) realpath() failed: %s\n",
+			name, strerror(errno));
+		rc = -1;
+		goto out;
+	}
+
+	len = strlen(p);
+	if (len + strlen(last_component) + 1 > PATH_MAX) {
+		fprintf(stderr, "symlink_realpath(%s) failed: Filename too long \n",
+			name);
+		rc = -1;
+		goto out;
+	}
+
+	resolved_path += len;
+	strcpy(resolved_path, last_component);
+out:
+	free(tmp_path);
+	return rc;
+}
+
 int main(int argc, char **argv)
 {
 	int i, init = 0, rc = 0;
@@ -105,50 +166,62 @@ int main(int argc, char **argv)
 	for (i = optind; i < argc; i++) {
 		int mode = 0;
 		struct stat buf;
-		int len = strlen(argv[i]);
-		if (len > 1  && argv[i][len - 1 ] == '/') {
-			argv[i][len - 1 ] = '\0';
-		}
+		char *p, *path = argv[i];
+		char stackpath[PATH_MAX + 1];
+		int len = strlen(path);
+		if (len > 1  && path[len - 1 ] == '/')
+			path[len - 1 ] = '\0';
 
-		if (lstat(argv[i], &buf) == 0)
+		if (lstat(path, &buf) == 0)
 			mode = buf.st_mode;
 
+		if (S_ISLNK(mode)) {
+			rc = symlink_realpath(path, stackpath);
+			if (!rc)
+				path = stackpath;
+		} else {
+			p = realpath(path, stackpath);
+			if (p)
+				path = p;
+		}
+
 		if (verify) {
+			rc = selinux_file_context_verify(path, mode);
+
 			if (quiet) {
-				if ((rc = selinux_file_context_verify(argv[i], mode)) == 1)
+				if (rc == 1)
 					continue;
 				else
 					exit(1);
 			}
 
-			rc = selinux_file_context_verify(argv[i], mode);
 			if (rc == -1) {
-				printf("%s error: %s\n", argv[i], strerror(errno));
+				printf("%s error: %s\n", path, strerror(errno));
 				exit(1);
-			} else if (rc == 1)
-				printf("%s verified.\n", argv[i]);
-			else {
+			} else if (rc == 1) {
+				printf("%s verified.\n", path);
+			} else {
 				security_context_t con;
 				error = 1;
 				if (notrans)
-					rc = lgetfilecon_raw(argv[i], &con);
+					rc = lgetfilecon_raw(path, &con);
 				else
-					rc = lgetfilecon(argv[i], &con);
+					rc = lgetfilecon(path, &con);
 
 				if (rc >= 0) {
 					printf("%s has context %s, should be ",
-					       argv[i], con);
-					printmatchpathcon(argv[i], 0, mode);
+					       path, con);
+					printmatchpathcon(path, 0, mode);
 					freecon(con);
 				} else {
 					printf
 					    ("actual context unknown: %s, should be ",
 					     strerror(errno));
-					printmatchpathcon(argv[i], 0, mode);
+					printmatchpathcon(path, 0, mode);
 				}
 			}
 		} else {
-			error |= printmatchpathcon(argv[i], header, mode);
+			error |= printmatchpathcon(path, header, mode);
 		}
 	}
 	matchpathcon_fini();
-- 
1.7.6

Attachment: 0004-libselinux-resolv-symlinks-and-dot-directories-befor.patch.sig
Description: PGP signature


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

  Powered by Linux