btrfs-progs: optionally enforce chroot for btrfs receive
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> [added long option variant, added docs] Signed-off-by: David Sterba <dsterba@suse.cz>
This commit is contained in:
parent
7732e6ef62
commit
9a86668071
|
@ -7,7 +7,7 @@ btrfs-receive - receive subvolumes from stdin/file.
|
|||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*btrfs receive* [-ve] [-f <infile>] [--max-errors <N>] <mount>
|
||||
*btrfs receive* [options] <mount>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -34,6 +34,8 @@ verbose level more.
|
|||
-f <infile>::
|
||||
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 <mount> using chroot.
|
||||
-e::
|
||||
Terminate after receiving an <end cmd> in the data stream.
|
||||
Without this option, the receiver terminates only if an error is recognized
|
||||
|
|
|
@ -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 <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.",
|
||||
|
|
Loading…
Reference in New Issue