tests: Add tests for the thumbnail verification code in GIO
authorPhilip Withnall <philip.withnall@collabora.co.uk>
Thu, 24 Oct 2013 11:09:27 +0000 (12:09 +0100)
committerRyan Lortie <desrt@desrt.ca>
Thu, 24 Oct 2013 17:55:33 +0000 (13:55 -0400)
This code was added for use by the G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID
file attribute, but may end up being used elsewhere (e.g. in GVfs) as well.
As it’s dealing with untrusted external files, and the non-trivial PNG file
format, this commit adds several test cases to cover valid and invalid PNG
files.

The security model for the thumbnail verification code is that the user’s
cache directory is untrusted, and potentially any PNG file which is passed
to the verifier has been manipulated arbitrarily by an attacker.

This is a follow-up to commit fe7069749fe39a006985ec266260a3c02ee8c855.

https://bugzilla.gnome.org/show_bug.cgi?id=709898

14 files changed:
gio/tests/.gitignore
gio/tests/Makefile.am
gio/tests/thumbnail-verification.c [new file with mode: 0644]
gio/tests/thumbnails/bad-header.png [new file with mode: 0644]
gio/tests/thumbnails/empty-key.png [new file with mode: 0644]
gio/tests/thumbnails/header-and-chunk-size.png [new file with mode: 0644]
gio/tests/thumbnails/header-only.png [new file with mode: 0644]
gio/tests/thumbnails/huge-chunk-size.png [new file with mode: 0644]
gio/tests/thumbnails/mtime-zero.png [new file with mode: 0644]
gio/tests/thumbnails/no-text-data.png [new file with mode: 0644]
gio/tests/thumbnails/overlong-value.png [new file with mode: 0644]
gio/tests/thumbnails/uri-mismatch.png [new file with mode: 0644]
gio/tests/thumbnails/valid-no-size.png [new file with mode: 0644]
gio/tests/thumbnails/valid.png [new file with mode: 0644]

index a211dc8..402f76b 100644 (file)
@@ -116,6 +116,7 @@ test.gresource
 test_resources.c
 test_resources2.c
 test_resources2.h
+thumbnail-verification
 tls-certificate
 tls-interaction
 unix-fd
index 55991b9..3d9d475 100644 (file)
@@ -176,6 +176,23 @@ schema_tests = \
        wrong-category.gschema.xml                      \
        $(NULL)
 
+test_programs += thumbnail-verification
+dist_test_data += $(thumbnail_data_files)
+thumbnail_data_files = $(addprefix thumbnails/,$(thumbnail_tests))
+thumbnail_tests = \
+       bad-header.png \
+       empty-key.png \
+       header-and-chunk-size.png \
+       header-only.png \
+       huge-chunk-size.png \
+       mtime-zero.png \
+       no-text-data.png \
+       overlong-value.png \
+       uri-mismatch.png \
+       valid.png \
+       valid-no-size.png \
+       $(NULL)
+
 test_programs += tls-certificate
 tls_certificate_SOURCES = \
        tls-certificate.c                       \
diff --git a/gio/tests/thumbnail-verification.c b/gio/tests/thumbnail-verification.c
new file mode 100644 (file)
index 0000000..6ccf48d
--- /dev/null
@@ -0,0 +1,121 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright (C) 2013 Collabora, Ltd.
+ *
+ * This work is provided "as is"; redistribution and modification
+ * in whole or in part, in any medium, physical or electronic is
+ * permitted without restriction.
+ *
+ * This work is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * In no event shall the authors or contributors be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability, whether
+ * in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even
+ * if advised of the possibility of such damage.
+ *
+ * Author: Philip Withnall <philip.withnall@collabora.co.uk>
+ */
+
+#include "../thumbnail-verify.c"
+
+static void
+test_validity (void)
+{
+  struct
+    {
+      const gchar *filename;  /* name of a file in the tests/thumbnails dir */
+      guint64 mtime;  /* asserted mtime of @filename */
+      guint64 size;  /* asserted size of @filename */
+      gboolean expected_validity;  /* should thumbnail_verify() succeed? */
+    }
+  tests[] =
+    {
+      /*
+       * Tests with well-formed PNG files.
+       *
+       * Note that these files have all been brutally truncated to a reasonable
+       * size, so aren't actually valid PNG files. Their headers are valid,
+       * however, and that's all we care about.
+       */
+
+      /* Test that validation succeeds against a valid PNG file with URI,
+       * mtime and size which match the expected values. */
+      { "valid.png", 1382429848, 93654, TRUE },
+      /* Test that validation succeeds with URI and mtime, but no size in the
+       * tEXt data. */
+      { "valid-no-size.png", 1382429848, 93633, TRUE },
+      /* Test that a missing file fails validation. */
+      { "missing.png", 123456789, 12345, FALSE },
+      /* Test that an existing file with no tEXt data fails validation. */
+      { "no-text-data.png", 123 /* invalid */, 26378, FALSE },
+      /* Test that a URI mismatch fails validation. */
+      { "uri-mismatch.png" /* invalid */, 1382429848, 93654, FALSE },
+      /* Test that an mtime mismatch fails validation. */
+      { "valid.png", 123 /* invalid */, 93654, FALSE },
+      /* Test that a valid URI and mtime, but a mismatched size, fails
+       * validation. */
+      { "valid.png", 1382429848, 123 /* invalid */, FALSE },
+      /* Test that validation succeeds with an mtime of 0. */
+      { "mtime-zero.png", 0, 93621, TRUE },
+      /* Test that validation fails if the mtime is only a prefix match. */
+      { "valid.png", 9848 /* invalid */, 93654, FALSE },
+
+      /*
+       * Tests with PNG files which have malicious or badly-formed headers.
+       *
+       * As above, the files have all been truncated to reduce their size.
+       */
+
+      /* Check a corrupted PNG header fails validation. */
+      { "bad-header.png", 1382429848, 93654, FALSE },
+      /* Check a PNG header by itself fails. */
+      { "header-only.png", 1382429848, 8, FALSE },
+      /* Check a PNG header and initial chunk size fails. */
+      { "header-and-chunk-size.png", 1382429848, 20, FALSE },
+      /* Check a huge chunk size fails. */
+      { "huge-chunk-size.png", 1382429848, 93654, FALSE },
+      /* Check that an empty key fails. */
+      { "empty-key.png", 1382429848, 93654, FALSE },
+      /* Check that an over-long value fails (even if nul-terminated). */
+      { "overlong-value.png", 1382429848, 93660, FALSE },
+    };
+  guint i;
+
+  /* Run all the tests. */
+  for (i = 0; i < G_N_ELEMENTS (tests); i++)
+    {
+      GStatBuf stat_buf;
+      const gchar *thumbnail_path;
+      gchar *file_uri;
+      gboolean result;
+
+      thumbnail_path = g_test_get_filename (G_TEST_DIST, "thumbnails",
+                                            tests[i].filename, NULL);
+      file_uri = g_strconcat ("file:///tmp/", tests[i].filename, NULL);
+      stat_buf.st_mtime = tests[i].mtime;
+      stat_buf.st_size = tests[i].size;
+
+      result = thumbnail_verify (thumbnail_path, file_uri, &stat_buf);
+
+      g_free (file_uri);
+
+      g_assert (result == tests[i].expected_validity);
+    }
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/png-thumbs/validity", test_validity);
+
+  return g_test_run ();
+}
diff --git a/gio/tests/thumbnails/bad-header.png b/gio/tests/thumbnails/bad-header.png
new file mode 100644 (file)
index 0000000..36c1524
Binary files /dev/null and b/gio/tests/thumbnails/bad-header.png differ
diff --git a/gio/tests/thumbnails/empty-key.png b/gio/tests/thumbnails/empty-key.png
new file mode 100644 (file)
index 0000000..b020881
Binary files /dev/null and b/gio/tests/thumbnails/empty-key.png differ
diff --git a/gio/tests/thumbnails/header-and-chunk-size.png b/gio/tests/thumbnails/header-and-chunk-size.png
new file mode 100644 (file)
index 0000000..1fdf444
Binary files /dev/null and b/gio/tests/thumbnails/header-and-chunk-size.png differ
diff --git a/gio/tests/thumbnails/header-only.png b/gio/tests/thumbnails/header-only.png
new file mode 100644 (file)
index 0000000..91d64e9
--- /dev/null
@@ -0,0 +1,2 @@
+\89PNG
+\1a
diff --git a/gio/tests/thumbnails/huge-chunk-size.png b/gio/tests/thumbnails/huge-chunk-size.png
new file mode 100644 (file)
index 0000000..7308553
Binary files /dev/null and b/gio/tests/thumbnails/huge-chunk-size.png differ
diff --git a/gio/tests/thumbnails/mtime-zero.png b/gio/tests/thumbnails/mtime-zero.png
new file mode 100644 (file)
index 0000000..8bac5f9
Binary files /dev/null and b/gio/tests/thumbnails/mtime-zero.png differ
diff --git a/gio/tests/thumbnails/no-text-data.png b/gio/tests/thumbnails/no-text-data.png
new file mode 100644 (file)
index 0000000..2eae44a
Binary files /dev/null and b/gio/tests/thumbnails/no-text-data.png differ
diff --git a/gio/tests/thumbnails/overlong-value.png b/gio/tests/thumbnails/overlong-value.png
new file mode 100644 (file)
index 0000000..0f3c56e
Binary files /dev/null and b/gio/tests/thumbnails/overlong-value.png differ
diff --git a/gio/tests/thumbnails/uri-mismatch.png b/gio/tests/thumbnails/uri-mismatch.png
new file mode 100644 (file)
index 0000000..7629983
Binary files /dev/null and b/gio/tests/thumbnails/uri-mismatch.png differ
diff --git a/gio/tests/thumbnails/valid-no-size.png b/gio/tests/thumbnails/valid-no-size.png
new file mode 100644 (file)
index 0000000..7629983
Binary files /dev/null and b/gio/tests/thumbnails/valid-no-size.png differ
diff --git a/gio/tests/thumbnails/valid.png b/gio/tests/thumbnails/valid.png
new file mode 100644 (file)
index 0000000..cc43208
Binary files /dev/null and b/gio/tests/thumbnails/valid.png differ