tools: Specify format of disks (RHBZ#642934,CVE-2010-3851).
authorRichard W.M. Jones <rjones@redhat.com>
Fri, 22 Oct 2010 09:59:53 +0000 (10:59 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 22 Oct 2010 16:45:06 +0000 (17:45 +0100)
Sys::Guestfs::Lib is changed in two ways: firstly we take the format
string from libvirt and pass it to add_drive_opts.  Secondly we allow
an extra format =>  parameter to open_guest which allows the
format to be specified for disk images.

All the tools are changed to add an extra --format parameter allowing
the format to be specified for direct disk images.

inspector/virt-inspector
perl/lib/Sys/Guestfs/Lib.pm
tools/virt-cat
tools/virt-edit
tools/virt-list-filesystems
tools/virt-list-partitions
tools/virt-ls
tools/virt-rescue
tools/virt-tar
tools/virt-win-reg

index bfaa50e..36fbfa9 100755 (executable)
@@ -107,6 +107,23 @@ then libvirt is not used at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $output = "text";
 
 =back
 my $output = "text";
 
 =back
@@ -178,6 +195,7 @@ parse information out of the Registry for any Windows guest.
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
             "text" => sub { $output = "text" },
             "none" => sub { $output = "none" },
             "xml" => sub { $output = "xml" },
             "text" => sub { $output = "text" },
             "none" => sub { $output = "none" },
             "xml" => sub { $output = "xml" },
@@ -214,11 +232,11 @@ my @images;
 if ($uri) {
     my ($conn, $dom);
     ($g, $conn, $dom, @images) =
 if ($uri) {
     my ($conn, $dom);
     ($g, $conn, $dom, @images) =
-        open_guest (\@ARGV, rw => $rw, address => $uri);
+        open_guest (\@ARGV, rw => $rw, address => $uri, format => $format);
 } else {
     my ($conn, $dom);
     ($g, $conn, $dom, @images) =
 } else {
     my ($conn, $dom);
     ($g, $conn, $dom, @images) =
-        open_guest (\@ARGV, rw => $rw);
+        open_guest (\@ARGV, rw => $rw, format => $format);
 }
 
 $g->launch ();
 }
 
 $g->launch ();
@@ -308,7 +326,12 @@ if ($output eq "fish" || $output eq "ro-fish") {
     }
 
     foreach (@images) {
     }
 
     foreach (@images) {
-        printf "-a %s ", shell_quote ($_);
+        unless (defined $_->[1]) {
+            printf "-a %s ", shell_quote ($_->[0]);
+        } else {
+            printf "--format %s -a %s ",
+              shell_quote ($_->[1]), shell_quote ($_->[0]);
+        }
     }
 
     my $mounts = $oses->{$root_dev}->{mounts};
     }
 
     my $mounts = $oses->{$root_dev}->{mounts};
index bb97506..2292839 100644 (file)
@@ -88,7 +88,7 @@ use vars qw(@EXPORT_OK @ISA);
 
  $g = open_guest ($name, address => $uri, ...);
 
 
  $g = open_guest ($name, address => $uri, ...);
 
- $g = open_guest ([$img1, $img2, ...], address => $uri, ...);
+ $g = open_guest ([$img1, $img2, ...], address => $uri, format => $format, ...);
 
  ($g, $conn, $dom, @images) = open_guest ($name);
 
 
  ($g, $conn, $dom, @images) = open_guest ($name);
 
@@ -103,7 +103,8 @@ block.
 
 The first parameter is either a string referring to a libvirt domain
 or a disk image, or (if a guest has several disk images) an arrayref
 
 The first parameter is either a string referring to a libvirt domain
 or a disk image, or (if a guest has several disk images) an arrayref
-C<[$img1, $img2, ...]>.
+C<[$img1, $img2, ...]>.  For disk images, if the C<format> parameter
+is specified then that format is forced.
 
 The handle is I<read-only> by default.  Use the optional parameter
 C<rw =E<gt> 1> to open a read-write handle.  However if you open a
 
 The handle is I<read-only> by default.  Use the optional parameter
 C<rw =E<gt> 1> to open a read-write handle.  However if you open a
@@ -120,16 +121,16 @@ The implicit libvirt handle is closed after this function, I<unless>
 you call the function in C<wantarray> context, in which case the
 function returns a tuple of: the open libguestfs handle, the open
 libvirt handle, and the open libvirt domain handle, and a list of
 you call the function in C<wantarray> context, in which case the
 function returns a tuple of: the open libguestfs handle, the open
 libvirt handle, and the open libvirt domain handle, and a list of
-images.  (This is useful if you want to do other things like pulling
-the XML description of the guest).  Note that if this is a straight
-disk image, then C<$conn> and C<$dom> will be C<undef>.
+[image,format] pairs.  (This is useful if you want to do other things
+like pulling the XML description of the guest).  Note that if this is
+a straight disk image, then C<$conn> and C<$dom> will be C<undef>.
 
 If the C<Sys::Virt> module is not available, then libvirt is bypassed,
 and this function can only open disk images.
 
 
 If the C<Sys::Virt> module is not available, then libvirt is bypassed,
 and this function can only open disk images.
 
-The optional C<interface> parameter can be used to open devices with
-C<add_drive{,_ro}_with_if>.  See
-L<Sys::Guestfs/guestfs_add_drive_with_if> for more details.
+The optional C<interface> parameter can be used to open devices with a
+specified qemu interface.  See L<Sys::Guestfs/guestfs_add_drive_opts>
+for more details.
 
 =cut
 
 
 =cut
 
@@ -142,6 +143,7 @@ sub open_guest
     my $rw = $params{rw};
     my $address = $params{address};
     my $interface = $params{interface};
     my $rw = $params{rw};
     my $address = $params{address};
     my $interface = $params{interface};
+    my $format = $params{format}; # undef == autodetect
 
     my @images = ();
     if (ref ($first) eq "ARRAY") {
 
     my @images = ();
     if (ref ($first) eq "ARRAY") {
@@ -167,6 +169,8 @@ sub open_guest
                     imagename => $_)
                 unless -r $_;
         }
                     imagename => $_)
                 unless -r $_;
         }
+
+        @images = map { [ $_, $format ] } @images;
     } else {
         die __"open_guest: no libvirt support (install Sys::Virt, XML::XPath and XML::XPath::XMLParser)"
             unless exists $INC{"Sys/Virt.pm"} &&
     } else {
         die __"open_guest: no libvirt support (install Sys::Virt, XML::XPath and XML::XPath::XMLParser)"
             unless exists $INC{"Sys/Virt.pm"} &&
@@ -211,32 +215,41 @@ sub open_guest
         my $xml = $dom->get_xml_description ();
 
         my $p = XML::XPath->new (xml => $xml);
         my $xml = $dom->get_xml_description ();
 
         my $p = XML::XPath->new (xml => $xml);
-        my @disks = $p->findnodes ('//devices/disk/source/@dev');
-        push (@disks, $p->findnodes ('//devices/disk/source/@file'));
+        my $nodes = $p->find ('//devices/disk');
+
+        my @disks = ();
+        my $node;
+        foreach $node ($nodes->get_nodelist) {
+            # The filename can be in dev or file attribute, hence:
+            my $filename = $p->find ('./source/@dev', $node);
+            unless ($filename) {
+                $filename = $p->find ('./source/@file', $node);
+                next unless $filename;
+            }
+            $filename = $filename->to_literal;
+
+            # Get the disk format (may not be set).
+            my $format = $p->find ('./driver/@type', $node);
+            $format = $format->to_literal if $format;
+
+            push @disks, [ $filename, $format ];
+        }
 
         die __x("{imagename} seems to have no disk devices\n",
                 imagename => $images[0])
             unless @disks;
 
 
         die __x("{imagename} seems to have no disk devices\n",
                 imagename => $images[0])
             unless @disks;
 
-        @images = map { $_->getData } @disks;
+        @images = @disks;
     }
 
     # We've now got the list of @images, so feed them to libguestfs.
     my $g = Sys::Guestfs->new ();
     foreach (@images) {
     }
 
     # We've now got the list of @images, so feed them to libguestfs.
     my $g = Sys::Guestfs->new ();
     foreach (@images) {
-        if ($rw) {
-            if ($interface) {
-                $g->add_drive_with_if ($_, $interface);
-            } else {
-                $g->add_drive ($_);
-            }
-        } else {
-            if ($interface) {
-                $g->add_drive_ro_with_if ($_, $interface);
-            } else {
-                $g->add_drive_ro ($_);
-            }
-        }
+        my @args = ($_->[0]);
+        push @args, format => $_->[1] if defined $_->[1];
+        push @args, readonly => 1 unless $rw;
+        push @args, iface => $interface if defined $interface;
+        $g->add_drive_opts (@args);
     }
 
     return wantarray ? ($g, $conn, $dom, @images) : $g
     }
 
     return wantarray ? ($g, $conn, $dom, @images) : $g
index 67506c0..66806a1 100755 (executable)
@@ -109,6 +109,23 @@ connect to the default libvirt hypervisor.
 If you specify guest block devices directly, then libvirt is not used
 at all.
 
 If you specify guest block devices directly, then libvirt is not used
 at all.
 
+=cut
+
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
 =back
 
 =cut
 =back
 
 =cut
@@ -116,6 +133,7 @@ at all.
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
     ) or pod2usage (2);
 pod2usage (1) if $help;
 if ($version) {
     ) or pod2usage (2);
 pod2usage (1) if $help;
 if ($version) {
@@ -132,9 +150,9 @@ my $filename = pop @ARGV;
 
 my $g;
 if ($uri) {
 
 my $g;
 if ($uri) {
-    $g = open_guest (\@ARGV, address => $uri);
+    $g = open_guest (\@ARGV, address => $uri, format => $format);
 } else {
 } else {
-    $g = open_guest (\@ARGV);
+    $g = open_guest (\@ARGV, format => $format);
 }
 
 $g->launch ();
 }
 
 $g->launch ();
index 59b5b2b..887ef4b 100755 (executable)
@@ -120,6 +120,23 @@ at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $expr;
 
 =item B<--expr EXPR> | B<-e EXPR>
 my $expr;
 
 =item B<--expr EXPR> | B<-e EXPR>
@@ -138,6 +155,7 @@ being altered by the shell.
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
             "expr|e=s" => \$expr,
             "backup|b=s" => \$backup,
     ) or pod2usage (2);
             "expr|e=s" => \$expr,
             "backup|b=s" => \$backup,
     ) or pod2usage (2);
@@ -156,9 +174,9 @@ my $filename = pop @ARGV;
 
 my $g;
 if ($uri) {
 
 my $g;
 if ($uri) {
-    $g = open_guest (\@ARGV, address => $uri, rw => 1);
+    $g = open_guest (\@ARGV, address => $uri, rw => 1, format => $format);
 } else {
 } else {
-    $g = open_guest (\@ARGV, rw => 1);
+    $g = open_guest (\@ARGV, rw => 1, format => $format);
 }
 
 $g->launch ();
 }
 
 $g->launch ();
index 7b4d5ad..5f545cf 100755 (executable)
@@ -81,6 +81,23 @@ at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $long;
 
 =item B<-l> | B<--long>
 my $long;
 
 =item B<-l> | B<--long>
@@ -107,6 +124,7 @@ Getopt::Long::Configure ("bundling");
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
             "long|l" => \$long,
             "all|a" => \$all,
     ) or pod2usage (2);
             "long|l" => \$long,
             "all|a" => \$all,
     ) or pod2usage (2);
@@ -123,9 +141,9 @@ pod2usage (__"virt-list-filesystems: no image or VM name given")
 
 my $g;
 if ($uri) {
 
 my $g;
 if ($uri) {
-    $g = open_guest (\@ARGV, address => $uri);
+    $g = open_guest (\@ARGV, address => $uri, format => $format);
 } else {
 } else {
-    $g = open_guest (\@ARGV);
+    $g = open_guest (\@ARGV, format => $format);
 }
 
 $g->launch ();
 }
 
 $g->launch ();
index 0edecc4..53059b4 100755 (executable)
@@ -82,6 +82,23 @@ at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $human;
 
 =item B<-h> | B<--human-readable>
 my $human;
 
 =item B<-h> | B<--human-readable>
@@ -116,6 +133,7 @@ Getopt::Long::Configure ("bundling");
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
             "human-readable|h" => \$human,
             "long|l" => \$long,
             "total|t" => \$total,
             "human-readable|h" => \$human,
             "long|l" => \$long,
             "total|t" => \$total,
@@ -133,9 +151,9 @@ pod2usage (__"virt-list-partitions: no image or VM name given")
 
 my $g;
 if ($uri) {
 
 my $g;
 if ($uri) {
-    $g = open_guest (\@ARGV, address => $uri);
+    $g = open_guest (\@ARGV, address => $uri, format => $format);
 } else {
 } else {
-    $g = open_guest (\@ARGV);
+    $g = open_guest (\@ARGV, format => $format);
 }
 
 $g->launch ();
 }
 
 $g->launch ();
index 9271a91..f0ac3f3 100755 (executable)
@@ -110,6 +110,23 @@ at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $mode;
 
 =item B<-l> | B<--long>
 my $mode;
 
 =item B<-l> | B<--long>
@@ -147,6 +164,7 @@ sub set_mode_R
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
             "long|l" => \&set_mode_l,
             "recursive|R" => \&set_mode_R,
     ) or pod2usage (2);
             "long|l" => \&set_mode_l,
             "recursive|R" => \&set_mode_R,
     ) or pod2usage (2);
@@ -165,9 +183,9 @@ my $directory = pop @ARGV;
 
 my $g;
 if ($uri) {
 
 my $g;
 if ($uri) {
-    $g = open_guest (\@ARGV, address => $uri);
+    $g = open_guest (\@ARGV, address => $uri, format => $format);
 } else {
 } else {
-    $g = open_guest (\@ARGV);
+    $g = open_guest (\@ARGV, format => $format);
 }
 
 $g->launch ();
 }
 
 $g->launch ();
index b8902a5..40245c7 100755 (executable)
@@ -142,6 +142,23 @@ at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $memsize;
 
 =item B<--memsize MB> | B<-m MB>
 my $memsize;
 
 =item B<--memsize MB> | B<-m MB>
@@ -180,6 +197,7 @@ GetOptions ("help|?" => \$help,
             "version" => \$version,
             "append=s" => \$append,
             "connect|c=s" => \$uri,
             "version" => \$version,
             "append=s" => \$append,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
             "memsize|m=i" => \$memsize,
             "ro|r" => \$readonly,
             "selinux" => \$selinux,
             "memsize|m=i" => \$memsize,
             "ro|r" => \$readonly,
             "selinux" => \$selinux,
@@ -198,6 +216,7 @@ pod2usage (__"virt-rescue: no image or VM names rescue given")
 my @args = (\@ARGV);
 push @args, address => $uri if $uri;
 push @args, rw => 1 unless $readonly;
 my @args = (\@ARGV);
 push @args, address => $uri if $uri;
 push @args, rw => 1 unless $readonly;
+push @args, format => $format if defined $format;
 my $g = open_guest (@args);
 
 # Setting "direct mode" is required for the rescue appliance.
 my $g = open_guest (@args);
 
 # Setting "direct mode" is required for the rescue appliance.
index 5e6e95a..ea33fcf 100755 (executable)
@@ -130,6 +130,23 @@ at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $mode;
 
 =item B<-x> | B<--extract> | B<--download>
 my $mode;
 
 =item B<-x> | B<--extract> | B<--download>
@@ -175,6 +192,7 @@ Getopt::Long::Configure ("bundling");
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
 GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
+            "format=s" => \$format,
             "extract|download|x" => \&set_mode_x,
             "upload|u" => \&set_mode_u,
             "gzip|z" => \$gzip,
             "extract|download|x" => \&set_mode_x,
             "upload|u" => \&set_mode_u,
             "gzip|z" => \$gzip,
@@ -211,6 +229,7 @@ die __x("virt-tar: {dir}: directory name must start with '/' character\n",
 my @args = (\@ARGV);
 push @args, address => $uri if $uri;
 push @args, rw => 1 if $mode eq "u";
 my @args = (\@ARGV);
 push @args, address => $uri if $uri;
 push @args, rw => 1 if $mode eq "u";
+push @args, format => $format if defined $format;
 
 my $g = open_guest (@args);
 $g->launch ();
 
 my $g = open_guest (@args);
 $g->launch ();
index 16688f4..ed298fb 100755 (executable)
@@ -211,6 +211,23 @@ at all.
 
 =cut
 
 
 =cut
 
+my $format;
+
+=item B<--format> raw
+
+Specify the format of disk images given on the command line.  If this
+is omitted then the format is autodetected from the content of the
+disk image.
+
+If disk images are requested from libvirt, then this program asks
+libvirt for this information.  In this case, the value of the format
+parameter is ignored.
+
+If working with untrusted raw-format guest disk images, you should
+ensure the format is always specified.
+
+=cut
+
 my $merge;
 
 =item B<--merge>
 my $merge;
 
 =item B<--merge>
@@ -244,6 +261,7 @@ GetOptions ("help|?" => \$help,
             "version" => \$version,
             "connect|c=s" => \$uri,
             "debug|d" => \$debug,
             "version" => \$version,
             "connect|c=s" => \$uri,
             "debug|d" => \$debug,
+            "format=s" => \$format,
             "merge" => \$merge,
             "encoding=s" => \$encoding,
     ) or pod2usage (2);
             "merge" => \$merge,
             "encoding=s" => \$encoding,
     ) or pod2usage (2);
@@ -264,6 +282,7 @@ warn "launching libguestfs ..." if $debug;
 my @lib_args = ([$domname_or_image]);
 push @lib_args, address => $uri if $uri;
 push @lib_args, rw => 1 if $merge;
 my @lib_args = ([$domname_or_image]);
 push @lib_args, address => $uri if $uri;
 push @lib_args, rw => 1 if $merge;
+push @lib_args, format => $format if defined $format;
 my $g = open_guest (@lib_args);
 $g->launch ();
 
 my $g = open_guest (@lib_args);
 $g->launch ();