Not enabled by default, because of the potential security concern that a client can use this to sniff what file names exist in the image; but for an opt-in setting in the server, this lets a single nbdkit process serve multiple files from an ext2 image (one at a time, unless we find a way to allow a filter to open the plugin once without a current connection, then share that opened plugin across multiple client connections). In testing this manually, I learned that qemu 4.0 fails to preserve leading / in nbd://host:port//path/to/file (no matter how many slashes you add), so the code here adds a leading slash to be nice to clients like broken qemu. Signed-off-by: Eric Blake <eblake@redhat.com> --- filters/ext2/ext2.c | 35 ++++++++++++++++++++--------- filters/ext2/nbdkit-ext2-filter.pod | 10 +++++++++ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/filters/ext2/ext2.c b/filters/ext2/ext2.c index d53743cd..92c8601a 100644 --- a/filters/ext2/ext2.c +++ b/filters/ext2/ext2.c @@ -50,7 +50,7 @@ #include "cleanup.h" #include "io.h" -/* Filename parameter. */ +/* Filename parameter, or NULL to honor export name. */ static char *file; static void @@ -94,7 +94,11 @@ ext2_config_complete (nbdkit_next_config_complete *next, void *nxdata) return -1; } - if (file[0] != '/') { + if (strcmp (file, "exportname") == 0) { + free (file); + file = NULL; + } + else if (file[0] != '/') { nbdkit_error ("the file parameter must refer to an absolute path"); return -1; } @@ -103,7 +107,8 @@ ext2_config_complete (nbdkit_next_config_complete *next, void *nxdata) } #define ext2_config_help \ - "ext2file=<FILENAME> (required) File to serve inside the disk image." + "ext2file=<FILENAME> (required) Absolute name of file to serve inside the\n" \ + " disk image, or 'exportname' for client choice." /* The per-connection handle. */ struct handle { @@ -143,6 +148,8 @@ ext2_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, struct ext2_inode inode; int64_t r; CLEANUP_FREE char *name = NULL; + const char *fname = file ?: nbdkit_export_name (); + CLEANUP_FREE char *absname = NULL; fs_flags = 0; #ifdef EXT2_FLAG_64BITS @@ -168,34 +175,42 @@ ext2_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, return -1; } + if (fname[0] != '/') { + if (asprintf (&absname, "/%s", fname) < 0) { + nbdkit_error ("asprintf: %m"); + return -1; + } + fname = absname; + } + err = ext2fs_open (name, fs_flags, 0, 0, nbdkit_io_manager, &h->fs); if (err != 0) { nbdkit_error ("open: %s", error_message (err)); goto err0; } - if (strcmp (file, "/") == 0) + if (strcmp (fname, "/") == 0) /* probably gonna fail, but we'll catch it later */ h->ino = EXT2_ROOT_INO; else { err = ext2fs_namei (h->fs, EXT2_ROOT_INO, EXT2_ROOT_INO, - &file[1], &h->ino); + &fname[1], &h->ino); if (err != 0) { - nbdkit_error ("%s: namei: %s", file, error_message (err)); + nbdkit_error ("%s: namei: %s", fname, error_message (err)); goto err1; } } - /* Check the file is a regular file. + /* Check that fname is a regular file. * XXX This won't follow symlinks, we'd have to do that manually. */ err = ext2fs_read_inode (h->fs, h->ino, &inode); if (err != 0) { - nbdkit_error ("%s: inode: %s", file, error_message (err)); + nbdkit_error ("%s: inode: %s", fname, error_message (err)); goto err1; } if (!LINUX_S_ISREG (inode.i_mode)) { - nbdkit_error ("%s: must be a regular file in the disk image", file); + nbdkit_error ("%s: must be a regular file in the disk image", fname); goto err1; } @@ -204,7 +219,7 @@ ext2_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, file_flags |= EXT2_FILE_WRITE; err = ext2fs_file_open2 (h->fs, h->ino, NULL, file_flags, &h->file); if (err != 0) { - nbdkit_error ("%s: open: %s", file, error_message (err)); + nbdkit_error ("%s: open: %s", fname, error_message (err)); goto err1; } diff --git a/filters/ext2/nbdkit-ext2-filter.pod b/filters/ext2/nbdkit-ext2-filter.pod index c0927637..d621ee45 100644 --- a/filters/ext2/nbdkit-ext2-filter.pod +++ b/filters/ext2/nbdkit-ext2-filter.pod @@ -7,6 +7,9 @@ ext4 filesystems nbdkit --filter=ext2 file fs.img ext2file=/disks/disk.raw + nbdkit --filter=ext2 --filter=partition file fs.img \ + partition=1 ext2file=exportname + =head1 DESCRIPTION C<nbdkit-ext2-filter> is an nbdkit filter which can read and @@ -55,6 +58,13 @@ e2fsprogs. The full path of the file within the filesystem that will be exposed over NBD. The path must be absolute (starts with C</>). +=item B<ext2file=exportname> + +The plugin will expose the path within the filesystem chosen by the +exportname passed by the client. Note that this mode allows the +client to deduce which files exist within the disk image, which may be +a security risk in some situations. + =back =head1 FILES -- 2.24.1