[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH 3/3] file: Restrict to regular files (RHBZ#582484).



I'm not entirely happy about the semantic change to the 'file' command
here, but symbolic links probably didn't work correctly before for the
majority of use cases, and this also fixes a potential DoS attack from
untrusted disk images.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines.  Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
>From 4df593496e116dfb635731c058b7627e81fc179c Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones redhat com>
Date: Fri, 4 Jun 2010 11:45:06 +0100
Subject: [PATCH 3/3] file: Restrict to regular files (RHBZ#582484).

The file call can hang if called on char devices (because we are
using the file -s option).

This is hard to solve cleanly without adding another file API.

However this restricts file to regular files, unless called explicitly
with a /dev/ path.  For non-regular files, it will now return a
string like "directory".

There is a small semantic change for symbolic links.  Previously
it would not have worked at all on absolute links (or rather, the
results would have been undefined).  It would have treated relative
symlinks to regular files as the regular file itself.  Now it will
return the string "symbolic link" in both cases.

This commit also makes the API safe when called on untrusted
filesystems.  Previously a filesystem might have been set up so
that (eg) /etc/redhat-release was a char device, which would have
caused virt-inspector and virt-v2v to hang.  Now it will not hang.
---
 daemon/file.c    |   46 +++++++++++++++++++++++++++++++++++-----------
 src/generator.ml |   23 ++++++++++++++++++-----
 2 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/daemon/file.c b/daemon/file.c
index 9824472..a55c606 100644
--- a/daemon/file.c
+++ b/daemon/file.c
@@ -544,21 +544,45 @@ do_file (const char *path)
       return NULL;
     }
     path = buf;
-  }
 
-  /* file(1) manpage claims "file returns 0 on success, and non-zero on
-   * error", but this is evidently not true.  It always returns 0, in
-   * every scenario I can think up.  So check the target is readable
-   * first.
-   */
-  if (access (path, R_OK) == -1) {
-    reply_with_perror ("access: %s", display_path);
-    free (buf);
-    return NULL;
+    /* For non-dev, check this is a regular file, else just return the
+     * file type as a string (RHBZ#582484).
+     */
+    struct stat statbuf;
+    if (lstat (path, &statbuf) == -1) {
+      reply_with_perror ("lstat: %s", display_path);
+      free (buf);
+      return NULL;
+    }
+
+    if (! S_ISREG (statbuf.st_mode)) {
+      char *ret;
+
+      free (buf);
+
+      if (S_ISDIR (statbuf.st_mode))
+        ret = strdup ("directory");
+      else if (S_ISCHR (statbuf.st_mode))
+        ret = strdup ("character device");
+      else if (S_ISBLK (statbuf.st_mode))
+        ret = strdup ("block device");
+      else if (S_ISFIFO (statbuf.st_mode))
+        ret = strdup ("FIFO");
+      else if (S_ISLNK (statbuf.st_mode))
+        ret = strdup ("symbolic link");
+      else if (S_ISSOCK (statbuf.st_mode))
+        ret = strdup ("socket");
+      else
+        ret = strdup ("unknown, not regular file");
+
+      if (ret == NULL)
+        reply_with_perror ("strdup");
+      return ret;
+    }
   }
 
   char *out, *err;
-  int r = command (&out, &err, "file", "-zbsL", path, NULL);
+  int r = command (&out, &err, "file", "-zbs", path, NULL);
   free (buf);
 
   if (r == -1) {
diff --git a/src/generator.ml b/src/generator.ml
index c7dbdfc..37d63f2 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -1632,19 +1632,32 @@ and physical volumes.");
     InitISOFS, Always, TestOutput (
       [["file"; "/known-1"]], "ASCII text");
     InitISOFS, Always, TestLastFail (
-      [["file"; "/notexists"]])],
+      [["file"; "/notexists"]]);
+    InitISOFS, Always, TestOutput (
+      [["file"; "/abssymlink"]], "symbolic link");
+    InitISOFS, Always, TestOutput (
+      [["file"; "/directory"]], "directory")],
    "determine file type",
    "\
 This call uses the standard L<file(1)> command to determine
-the type or contents of the file.  This also works on devices,
-for example to find out whether a partition contains a filesystem.
+the type or contents of the file.
 
 This call will also transparently look inside various types
 of compressed file.
 
-The exact command which runs is C<file -zbsL path>.  Note in
+The exact command which runs is C<file -zbs path>.  Note in
 particular that the filename is not prepended to the output
-(the C<-b> option).");
+(the C<-b> option).
+
+This command can also be used on C</dev/> devices
+(and partitions, LV names).  You can for example use this
+to determine if a device contains a filesystem, although
+it's usually better to use C<guestfs_vfs_type>.
+
+If the C<path> does not begin with C</dev/> then
+this command only works for the content of regular files.
+For other file types (directory, symbolic link etc) it
+will just return the string C<directory> etc.");
 
   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutput (
-- 
1.6.6.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]