mirror of
https://github.com/topjohnwu/selinux.git
synced 2025-02-24 05:13:36 +00:00
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@redhat.com> Acked-by: Dan Walsh <dwalsh@redhat.com>
This commit is contained in:
parent
5619635063
commit
4ad1896954
@ -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;
|
||||
@ -103,48 +164,62 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
for (i = optind; i < argc; i++) {
|
||||
int mode = 0;
|
||||
int rc, 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 (selinux_file_context_verify(argv[i], mode))
|
||||
if (rc)
|
||||
continue;
|
||||
else
|
||||
exit(1);
|
||||
}
|
||||
if (selinux_file_context_verify(argv[i], mode)) {
|
||||
printf("%s verified.\n", argv[i]);
|
||||
|
||||
if (rc) {
|
||||
printf("%s verified.\n", path);
|
||||
} else {
|
||||
security_context_t con;
|
||||
int rc;
|
||||
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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user