提交 72f0d0bf 编写于 作者: G Greg Kurz

9pfs: local: lremovexattr: don't follow symlinks

The local_lremovexattr() callback is vulnerable to symlink attacks because
it calls lremovexattr() which follows symbolic links in all path elements
but the rightmost one.

This patch introduces a helper to emulate the non-existing fremovexattrat()
function: it is implemented with /proc/self/fd which provides a trusted
path that can be safely passed to lremovexattr().

local_lremovexattr() is converted to use this helper and opendir_nofollow().

This partly fixes CVE-2016-9602.
Signed-off-by: NGreg Kurz <groug@kaod.org>
Reviewed-by: NStefan Hajnoczi <stefanha@redhat.com>
上级 3e36aba7
...@@ -58,10 +58,8 @@ static int mp_pacl_removexattr(FsContext *ctx, ...@@ -58,10 +58,8 @@ static int mp_pacl_removexattr(FsContext *ctx,
const char *path, const char *name) const char *path, const char *name)
{ {
int ret; int ret;
char *buffer;
buffer = rpath(ctx, path); ret = local_removexattr_nofollow(ctx, path, MAP_ACL_ACCESS);
ret = lremovexattr(buffer, MAP_ACL_ACCESS);
if (ret == -1 && errno == ENODATA) { if (ret == -1 && errno == ENODATA) {
/* /*
* We don't get ENODATA error when trying to remove a * We don't get ENODATA error when trying to remove a
...@@ -71,7 +69,6 @@ static int mp_pacl_removexattr(FsContext *ctx, ...@@ -71,7 +69,6 @@ static int mp_pacl_removexattr(FsContext *ctx,
errno = 0; errno = 0;
ret = 0; ret = 0;
} }
g_free(buffer);
return ret; return ret;
} }
...@@ -111,10 +108,8 @@ static int mp_dacl_removexattr(FsContext *ctx, ...@@ -111,10 +108,8 @@ static int mp_dacl_removexattr(FsContext *ctx,
const char *path, const char *name) const char *path, const char *name)
{ {
int ret; int ret;
char *buffer;
buffer = rpath(ctx, path); ret = local_removexattr_nofollow(ctx, path, MAP_ACL_DEFAULT);
ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
if (ret == -1 && errno == ENODATA) { if (ret == -1 && errno == ENODATA) {
/* /*
* We don't get ENODATA error when trying to remove a * We don't get ENODATA error when trying to remove a
...@@ -124,7 +119,6 @@ static int mp_dacl_removexattr(FsContext *ctx, ...@@ -124,7 +119,6 @@ static int mp_dacl_removexattr(FsContext *ctx,
errno = 0; errno = 0;
ret = 0; ret = 0;
} }
g_free(buffer);
return ret; return ret;
} }
......
...@@ -81,9 +81,6 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name, ...@@ -81,9 +81,6 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
static int mp_user_removexattr(FsContext *ctx, static int mp_user_removexattr(FsContext *ctx,
const char *path, const char *name) const char *path, const char *name)
{ {
char *buffer;
int ret;
if (strncmp(name, "user.virtfs.", 12) == 0) { if (strncmp(name, "user.virtfs.", 12) == 0) {
/* /*
* Don't allow fetch of user.virtfs namesapce * Don't allow fetch of user.virtfs namesapce
...@@ -92,10 +89,7 @@ static int mp_user_removexattr(FsContext *ctx, ...@@ -92,10 +89,7 @@ static int mp_user_removexattr(FsContext *ctx,
errno = EACCES; errno = EACCES;
return -1; return -1;
} }
buffer = rpath(ctx, path); return local_removexattr_nofollow(ctx, path, name);
ret = lremovexattr(buffer, name);
g_free(buffer);
return ret;
} }
XattrOperations mapped_user_xattr = { XattrOperations mapped_user_xattr = {
......
...@@ -234,17 +234,43 @@ int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, ...@@ -234,17 +234,43 @@ int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
return local_setxattr_nofollow(ctx, path, name, value, size, flags); return local_setxattr_nofollow(ctx, path, name, value, size, flags);
} }
int pt_removexattr(FsContext *ctx, const char *path, const char *name) static ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
const char *name)
{ {
char *buffer; char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
int ret; int ret;
buffer = rpath(ctx, path); ret = lremovexattr(proc_path, name);
ret = lremovexattr(path, name); g_free(proc_path);
g_free(buffer);
return ret; return ret;
} }
ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
const char *name)
{
char *dirpath = g_path_get_dirname(path);
char *filename = g_path_get_basename(path);
int dirfd;
ssize_t ret = -1;
dirfd = local_opendir_nofollow(ctx, dirpath);
if (dirfd == -1) {
goto out;
}
ret = fremovexattrat_nofollow(dirfd, filename, name);
close_preserve_errno(dirfd);
out:
g_free(dirpath);
g_free(filename);
return ret;
}
int pt_removexattr(FsContext *ctx, const char *path, const char *name)
{
return local_removexattr_nofollow(ctx, path, name);
}
ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size) void *value, size_t size)
{ {
......
...@@ -34,6 +34,8 @@ ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, ...@@ -34,6 +34,8 @@ ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path, ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
const char *name, void *value, size_t size, const char *name, void *value, size_t size,
int flags); int flags);
ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
const char *name);
extern XattrOperations mapped_user_xattr; extern XattrOperations mapped_user_xattr;
extern XattrOperations passthrough_user_xattr; extern XattrOperations passthrough_user_xattr;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册