diff options
author | Dan Cashman <dcashman@google.com> | 2015-09-10 09:42:15 -0700 |
---|---|---|
committer | dcashman <dcashman@google.com> | 2015-09-21 14:43:23 -0700 |
commit | 87ceb1e29e97a79091b51936c12f1f82d5a328d0 (patch) | |
tree | a047491a9b28d5c24cbb21cf8ec5623fd467dcde | |
parent | d4b197ab1b4a2d694114b2c127fe009326fb0958 (diff) | |
download | libselinux-87ceb1e29e97a79091b51936c12f1f82d5a328d0.tar.gz |
Enable restorecon to properly label symlinks.
commit: 06d45512e2df93f65a51877a51549e522b4f2cf5 changed restorecon to only
operate on paths which had undergone a realpath transformation. Unfortunately,
this made it impossible to directly restorecon a symlink, since the symlink
would be followed. Change restorecon to only perform realpath on the directory
prefix, so that symlinks can be labeled.
Bug: 21732016
Change-Id: Iebb5d5e9c637c2ef3da5d5674f73babf094af131
-rw-r--r-- | src/android.c | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/src/android.c b/src/android.c index 8f66a5a..f253954 100644 --- a/src/android.c +++ b/src/android.c @@ -31,6 +31,7 @@ #include <limits.h> #include <sys/vfs.h> #include <linux/magic.h> +#include <libgen.h> /* * XXX Where should this configuration file be located? @@ -1231,7 +1232,7 @@ static int selinux_android_restorecon_common(const char* pathname_orig, struct statfs sfsb; FTS *fts; FTSENT *ftsent; - char *pathname; + char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; char * paths[2] = { NULL , NULL }; int ftsflags = FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL; int error, sverrno; @@ -1246,16 +1247,28 @@ static int selinux_android_restorecon_common(const char* pathname_orig, if (!fc_sehandle) return 0; - // convert passed-in pathname to canonical pathname - pathname = realpath(pathname_orig, NULL); - if (!pathname) { - sverrno = errno; - selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path %s restorecon: %s.\n", - pathname_orig, strerror(errno)); - errno = sverrno; - error = -1; - goto cleanup; + /* + * Convert passed-in pathname to canonical pathname by resolving realpath of + * containing dir, then appending last component name. + */ + pathbname = basename(pathname_orig); + if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || !strcmp(pathbname, "..")) { + pathname = realpath(pathname_orig, NULL); + if (!pathname) + goto realpatherr; + } else { + pathdname = dirname(pathname_orig); + pathdnamer = realpath(pathdname, NULL); + if (!pathdnamer) + goto realpatherr; + if (!strcmp(pathdnamer, "/")) + error = asprintf(&pathname, "/%s", pathbname); + else + error = asprintf(&pathname, "%s/%s", pathdnamer, pathbname); + if (error < 0) + goto oom; } + paths[0] = pathname; issys = (!strcmp(pathname, SYS_PATH) || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false; @@ -1364,8 +1377,22 @@ out: (void) fts_close(fts); errno = sverrno; cleanup: + free(pathdnamer); free(pathname); return error; +oom: + sverrno = errno; + selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); + errno = sverrno; + error = -1; + goto cleanup; +realpatherr: + sverrno = errno; + selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %s.\n", + pathname_orig, strerror(errno)); + errno = sverrno; + error = -1; + goto cleanup; } int selinux_android_restorecon(const char *file, unsigned int flags) |