From 9a86668071e77b2da0173b8921153de4d7ba99d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauri=20V=C3=B5sandi?= Date: Sun, 19 Apr 2015 14:46:28 +0300 Subject: [PATCH] btrfs-progs: optionally enforce chroot for btrfs receive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch forces btrfs receive to issue chroot before parsing the btrfs stream using command-line flag -C to confine the process and minimize damage that could be done via malicious btrfs stream. Signed-off-by: Lauri Võsandi [added long option variant, added docs] Signed-off-by: David Sterba --- Documentation/btrfs-receive.asciidoc | 4 ++- cmds-receive.c | 49 +++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/Documentation/btrfs-receive.asciidoc b/Documentation/btrfs-receive.asciidoc index ed1e247f..bdbabdff 100644 --- a/Documentation/btrfs-receive.asciidoc +++ b/Documentation/btrfs-receive.asciidoc @@ -7,7 +7,7 @@ btrfs-receive - receive subvolumes from stdin/file. SYNOPSIS -------- -*btrfs receive* [-ve] [-f ] [--max-errors ] +*btrfs receive* [options] DESCRIPTION ----------- @@ -34,6 +34,8 @@ verbose level more. -f :: By default, btrfs receive uses stdin to receive the subvolumes. Use this option to specify a file to use instead. +-C|--chroot:: +Confine the process to using chroot. -e:: Terminate after receiving an in the data stream. Without this option, the receiver terminates only if an error is recognized diff --git a/cmds-receive.c b/cmds-receive.c index 919dc9e2..3505c76e 100644 --- a/cmds-receive.c +++ b/cmds-receive.c @@ -61,6 +61,7 @@ struct btrfs_receive char *root_path; char *dest_dir_path; /* relative to root_path */ char *full_subvol_path; + int dest_dir_chroot; struct subvol_info *cur_subvol; @@ -858,14 +859,38 @@ static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd, goto out; } - /* - * find_mount_root returns a root_path that is a subpath of - * dest_dir_full_path. Now get the other part of root_path, - * which is the destination dir relative to root_path. - */ - r->dest_dir_path = dest_dir_full_path + strlen(r->root_path); - while (r->dest_dir_path[0] == '/') - r->dest_dir_path++; + if (r->dest_dir_chroot) { + if (chroot(dest_dir_full_path)) { + ret = -errno; + fprintf(stderr, + "ERROR: failed to chroot to %s, %s\n", + dest_dir_full_path, + strerror(-ret)); + goto out; + } + if (chdir("/")) { + ret = -errno; + fprintf(stderr, + "ERROR: failed to chdir to /, %s\n", + strerror(-ret)); + goto out; + } + if (g_verbose >= 1) { + fprintf(stderr, "chrooted to %s\n", + dest_dir_full_path); + } + r->root_path = strdup("/"); + r->dest_dir_path = r->root_path; + } else { + /* + * find_mount_root returns a root_path that is a subpath of + * dest_dir_full_path. Now get the other part of root_path, + * which is the destination dir relative to root_path. + */ + r->dest_dir_path = dest_dir_full_path + strlen(r->root_path); + while (r->dest_dir_path[0] == '/') + r->dest_dir_path++; + } ret = subvol_uuid_search_init(r->mnt_fd, &r->sus); if (ret < 0) @@ -930,15 +955,17 @@ int cmd_receive(int argc, char **argv) r.mnt_fd = -1; r.write_fd = -1; r.dest_dir_fd = -1; + r.dest_dir_chroot = 0; while (1) { int c; static const struct option long_opts[] = { { "max-errors", required_argument, NULL, 'E' }, + { "chroot", no_argument, NULL, 'C' }, { NULL, 0, NULL, 0 } }; - c = getopt_long(argc, argv, "evf:", long_opts, NULL); + c = getopt_long(argc, argv, "Cevf:", long_opts, NULL); if (c < 0) break; @@ -952,6 +979,9 @@ int cmd_receive(int argc, char **argv) case 'e': r.honor_end_cmd = 1; break; + case 'C': + r.dest_dir_chroot = 1; + break; case 'E': max_errors = arg_strtou64(optarg); break; @@ -1001,6 +1031,7 @@ const char * const cmd_receive_usage[] = { " in the data stream. Without this option,", " the receiver terminates only if an error", " is recognized or on EOF.", + "-C|--chroot confine the process to using chroot", "--max-errors Terminate as soon as N errors happened while", " processing commands from the send stream.", " Default value is 1. A value of 0 means no limit.",