[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH RFC 31/36] 9pfs: local: introduce symlink-attack saf
From: |
Greg Kurz |
Subject: |
[Qemu-devel] [PATCH RFC 31/36] 9pfs: local: introduce symlink-attack safe xattr helpers |
Date: |
Mon, 30 Jan 2017 13:13:33 +0100 |
User-agent: |
StGit/0.17.1-20-gc0b1b-dirty |
There are no "at" variants for xattr syscalls. This patch implement them
using a separate process.
Signed-off-by: Greg Kurz <address@hidden>
---
hw/9pfs/9p-xattr.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/9pfs/9p-xattr.h | 11 ++++
2 files changed, 167 insertions(+)
diff --git a/hw/9pfs/9p-xattr.c b/hw/9pfs/9p-xattr.c
index 19a2daf02f5c..ea0695f37242 100644
--- a/hw/9pfs/9p-xattr.c
+++ b/hw/9pfs/9p-xattr.c
@@ -15,7 +15,163 @@
#include "9p.h"
#include "fsdev/file-op-9p.h"
#include "9p-xattr.h"
+#include "9p-util.h"
+enum {
+ XATTRAT_OP_GET = 0,
+ XATTRAT_OP_LIST,
+ XATTRAT_OP_SET,
+ XATTRAT_OP_REMOVE
+};
+
+struct xattrat_data {
+ ssize_t ret;
+ int serrno;
+ char value[0];
+};
+
+static void munmap_preserver_errno(void *addr, size_t length)
+{
+ int serrno = errno;
+ munmap(addr, length);
+ errno = serrno;
+}
+
+static ssize_t do_xattrat_op(int op_type, int dirfd, const char *path,
+ const char *name, void *value, size_t size,
+ int flags)
+{
+ struct xattrat_data *data;
+ pid_t pid;
+ ssize_t ret = -1;
+ int wstatus;
+
+ data = mmap(NULL, sizeof(*data) + size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (data == MAP_FAILED) {
+ return -1;
+ }
+ data->ret = -1;
+
+ pid = fork();
+ if (pid < 0) {
+ goto err_out;
+ } else if (pid == 0) {
+ if (fchdir(dirfd) == 0) {
+ switch (op_type) {
+ case XATTRAT_OP_GET:
+ data->ret = lgetxattr(path, name, data->value, size);
+ break;
+ case XATTRAT_OP_LIST:
+ data->ret = llistxattr(path, data->value, size);
+ break;
+ case XATTRAT_OP_SET:
+ data->ret = lsetxattr(path, name, data->value, size, flags);
+ break;
+ case XATTRAT_OP_REMOVE:
+ data->ret = lremovexattr(path, name);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ data->serrno = errno;
+ _exit(0);
+ }
+ assert(waitpid(pid, &wstatus, 0) == pid && WIFEXITED(wstatus));
+
+ ret = data->ret;
+ if (ret < 0) {
+ errno = data->serrno;
+ goto err_out;
+ }
+ memcpy(value, data->value, data->ret);
+
+err_out:
+ munmap_preserver_errno(data, sizeof(*data) + size);
+ return ret;
+}
+
+ssize_t fgetxattrat(int dirfd, const char *path, const char *name, void *value,
+ size_t size)
+{
+ return do_xattrat_op(XATTRAT_OP_GET, dirfd, path, name, value, size, 0);
+}
+
+ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size)
+{
+ char *dirpath = local_dirname(path);
+ char *filename = local_basename(path);
+ int dirfd;
+ ssize_t ret = -1;
+
+ dirfd = local_opendir_nofollow(ctx, dirpath);
+ if (dirfd == -1) {
+ goto out;
+ }
+
+ ret = fgetxattrat(dirfd, filename, name, value, size);
+ close_preserve_errno(dirfd);
+out:
+ g_free(dirpath);
+ g_free(filename);
+ return ret;
+}
+
+static ssize_t fsetxattrat(int dirfd, const char *path, const char *name,
+ void *value, size_t size, int flags)
+{
+ return do_xattrat_op(XATTRAT_OP_SET, dirfd, path, name, value, size,
flags);
+}
+
+ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size,
+ int flags)
+{
+ char *dirpath = local_dirname(path);
+ char *filename = local_basename(path);
+ int dirfd;
+ ssize_t ret = -1;
+
+ dirfd = local_opendir_nofollow(ctx, dirpath);
+ if (dirfd == -1) {
+ goto out;
+ }
+
+ ret = fsetxattrat(dirfd, filename, name, value, size, flags);
+ close_preserve_errno(dirfd);
+out:
+ g_free(dirpath);
+ g_free(filename);
+ return ret;
+}
+
+static ssize_t fremovexattrat(int dirfd, const char *path, const char *name)
+{
+ return do_xattrat_op(XATTRAT_OP_GET, dirfd, path, name, NULL, 0, 0);
+}
+
+ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
+ const char *name)
+{
+ char *dirpath = local_dirname(path);
+ char *filename = local_basename(path);
+ int dirfd;
+ ssize_t ret = -1;
+
+ dirfd = local_opendir_nofollow(ctx, dirpath);
+ if (dirfd == -1) {
+ goto out;
+ }
+
+ ret = fremovexattrat(dirfd, filename, name);
+ close_preserve_errno(dirfd);
+out:
+ g_free(dirpath);
+ g_free(filename);
+ return ret;
+}
static XattrOperations *get_xattr_operations(XattrOperations **h,
const char *name)
diff --git a/hw/9pfs/9p-xattr.h b/hw/9pfs/9p-xattr.h
index 3f43f5153f3c..d95ccc26a18d 100644
--- a/hw/9pfs/9p-xattr.h
+++ b/hw/9pfs/9p-xattr.h
@@ -15,6 +15,7 @@
#define QEMU_9P_XATTR_H
#include "qemu/xattr.h"
+#include "9p-local.h"
typedef struct xattr_operations
{
@@ -29,6 +30,16 @@ typedef struct xattr_operations
const char *path, const char *name);
} XattrOperations;
+ssize_t fgetxattrat(int dirfd, const char *path, const char *name, void *value,
+ size_t size);
+
+ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size);
+ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size,
+ int flags);
+ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
+ const char *name);
extern XattrOperations mapped_user_xattr;
extern XattrOperations passthrough_user_xattr;
- [Qemu-devel] [PATCH RFC 26/36] 9pfs: local: chown: don't follow symlinks, (continued)
- [Qemu-devel] [PATCH RFC 26/36] 9pfs: local: chown: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 27/36] 9pfs: local: link: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 28/36] 9pfs: local: rename: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 29/36] 9pfs: local: remove: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 30/36] 9pfs: local: unlinkat: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 32/36] 9pfs: local: lstat: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 33/36] 9pfs: local: lgetxattr: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 35/36] 9pfs: local: lsetxattr: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 36/36] 9pfs: local: lremovexattr: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 34/36] 9pfs: local: llistxattr: don't follow symlinks, Greg Kurz, 2017/01/30
- [Qemu-devel] [PATCH RFC 31/36] 9pfs: local: introduce symlink-attack safe xattr helpers,
Greg Kurz <=