Message ID | 1429365545-2419-1-git-send-email-lauri.vosandi@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
On 18 April 2015 at 14:59, Lauri Võsandi <lauri.vosandi@gmail.com> wrote: > 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 <lauri.vosandi@gmail.com> > --- > cmds-receive.c | 37 ++++++++++++++++++++++++++++--------- > 1 file changed, 28 insertions(+), 9 deletions(-) > > diff --git a/cmds-receive.c b/cmds-receive.c > index 44ef27e..73bd88b 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; > > @@ -867,14 +868,27 @@ 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)); There appears to be a goto out missing here. > + } > + if (g_verbose >= 1) { > + fprintf(stderr, "chrooted to %s\n", > + dest_dir_full_path); > + } > + r->root_path = r->dest_dir_path = strdup("/"); > + } > > ret = subvol_uuid_search_init(r->mnt_fd, &r->sus); > if (ret < 0) > @@ -940,6 +954,7 @@ int cmd_receive(int argc, char **argv) > r.write_fd = -1; > r.dest_dir_fd = -1; > r.explicit_parent = NULL; > + r.dest_dir_chroot = 0; > > while (1) { > int c; > @@ -948,7 +963,7 @@ int cmd_receive(int argc, char **argv) > { NULL, 0, NULL, 0 } > }; > > - c = getopt_long(argc, argv, "evf:p:", long_opts, NULL); > + c = getopt_long(argc, argv, "Cevf:p:", long_opts, NULL); > if (c < 0) > break; > > @@ -962,6 +977,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; > @@ -1014,6 +1032,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 Confine the process to <mount> using chroot", > "--max-errors <N> 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.", > -- > 1.9.1 Mike -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/cmds-receive.c b/cmds-receive.c index 44ef27e..73bd88b 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; @@ -867,14 +868,27 @@ 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)); + } + if (g_verbose >= 1) { + fprintf(stderr, "chrooted to %s\n", + dest_dir_full_path); + } + r->root_path = r->dest_dir_path = strdup("/"); + } ret = subvol_uuid_search_init(r->mnt_fd, &r->sus); if (ret < 0) @@ -940,6 +954,7 @@ int cmd_receive(int argc, char **argv) r.write_fd = -1; r.dest_dir_fd = -1; r.explicit_parent = NULL; + r.dest_dir_chroot = 0; while (1) { int c; @@ -948,7 +963,7 @@ int cmd_receive(int argc, char **argv) { NULL, 0, NULL, 0 } }; - c = getopt_long(argc, argv, "evf:p:", long_opts, NULL); + c = getopt_long(argc, argv, "Cevf:p:", long_opts, NULL); if (c < 0) break; @@ -962,6 +977,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; @@ -1014,6 +1032,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 Confine the process to <mount> using chroot", "--max-errors <N> 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.",
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 <lauri.vosandi@gmail.com> --- cmds-receive.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-)