-----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