From fcd2f7e63923853e113500e48005d269291cf391 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 24 Oct 2013 12:09:27 +0100 Subject: [PATCH] tests: Add tests for the thumbnail verification code in GIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- gio/tests/.gitignore | 1 + gio/tests/Makefile.am | 17 +++ gio/tests/thumbnail-verification.c | 121 ++++++++++++++++++ gio/tests/thumbnails/bad-header.png | Bin 0 -> 512 bytes gio/tests/thumbnails/empty-key.png | Bin 0 -> 512 bytes .../thumbnails/header-and-chunk-size.png | Bin 0 -> 20 bytes gio/tests/thumbnails/header-only.png | 2 + gio/tests/thumbnails/huge-chunk-size.png | Bin 0 -> 512 bytes gio/tests/thumbnails/mtime-zero.png | Bin 0 -> 512 bytes gio/tests/thumbnails/no-text-data.png | Bin 0 -> 256 bytes gio/tests/thumbnails/overlong-value.png | Bin 0 -> 512 bytes gio/tests/thumbnails/uri-mismatch.png | Bin 0 -> 512 bytes gio/tests/thumbnails/valid-no-size.png | Bin 0 -> 512 bytes gio/tests/thumbnails/valid.png | Bin 0 -> 512 bytes 14 files changed, 141 insertions(+) create mode 100644 gio/tests/thumbnail-verification.c create mode 100644 gio/tests/thumbnails/bad-header.png create mode 100644 gio/tests/thumbnails/empty-key.png create mode 100644 gio/tests/thumbnails/header-and-chunk-size.png create mode 100644 gio/tests/thumbnails/header-only.png create mode 100644 gio/tests/thumbnails/huge-chunk-size.png create mode 100644 gio/tests/thumbnails/mtime-zero.png create mode 100644 gio/tests/thumbnails/no-text-data.png create mode 100644 gio/tests/thumbnails/overlong-value.png create mode 100644 gio/tests/thumbnails/uri-mismatch.png create mode 100644 gio/tests/thumbnails/valid-no-size.png create mode 100644 gio/tests/thumbnails/valid.png diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore index a211dc85a..402f76b13 100644 --- a/gio/tests/.gitignore +++ b/gio/tests/.gitignore @@ -116,6 +116,7 @@ test.gresource test_resources.c test_resources2.c test_resources2.h +thumbnail-verification tls-certificate tls-interaction unix-fd diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index 55991b961..3d9d47530 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -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 index 000000000..6ccf48d7e --- /dev/null +++ b/gio/tests/thumbnail-verification.c @@ -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 + */ + +#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 index 0000000000000000000000000000000000000000..36c15249115d9ce2b10520937802bfa1f7d66ba8 GIT binary patch literal 512 zcmeAS@b`1)<&xrJU|`_&^l%9R(pMQ67#TR2fUMQamiz%y%*9TgAsieWw;%dH0CL4k zTq8rktgJk96Vp?ztim%>N-`LX4Gi8t(PsuKk-${qk(!yFQNmzsW*F=7!VjoM z14&J2kS9Z0W=^V=zP^4*Zh?MTVoqj?ZeG4_ab{JjUO`@ZC2!9;G^>3>GILWI42>;} zOpGioOf0_07aamBQ2-emoS#-wo>-L1;O^(|>uO~Mc5Pl_W{z88a!GzsWxh-31E5j{ zPZ!6Kia9-dJSVH1oT~QCEY!64dqmONGfufHm@Y7IIhY&l-4MM@vv?-+N#_47{7?2j zoa_F{oX54|p;}DK;hFCe`xi*_if~oyMoyh5`0!oYs$XJqSCl8rIOfyenbOt1yS;kG zt;^r{eXqT59AfL@(&FB-+nIrJhqWVLfdzx%v>t?LxqM+G}-$AyM4EFCsxMtark*`4Kwa`Nb}QV zY*;zlnrVvW?3t_j@{Kol2uz%_d8S~Yak|Q8911Ltkuhw`~gzT#ZI0f92^|CANoH4a>Ywr zBT7OtN^_H}tUPlQ(^IXi!ZTA!G8l{v4BkJ{X9g;fz*ORqnwg$a!eDG>80+!E52!`~ zq=o@vOlXiNLt17|s+GRJeo1bDepzBpW{O@xUV0^O&pDu4K_v5nGpkY=ERD@fO`wv< z?(q%D%uQu5G`27@F|xEUvG^iibO>fwaDG}zd16s2gS(%!(Sg6RSSmxH;%-VM>qG>d04 zpJe{e!vAFd!@2IC%z0cZ9;(H(9G>|uv44RyuLxJQZsgR7f)C%Nt@#YP+Z{gjX_CG@Cl1U zK|Kot!vf}>e#Q^qPOks=uKvgS|GUrI*Sb!zeN=Emf9thd&(8L^yxVs>cVcBMABUgE z)-dC4hcrJ;#)g%%t(m51&YrodFW-1`hrq-+n`a6Z8mFs#%8T;+6!`G;?Wg;Htp@;8 Cu)!?= literal 0 HcmV?d00001 diff --git a/gio/tests/thumbnails/header-and-chunk-size.png b/gio/tests/thumbnails/header-and-chunk-size.png new file mode 100644 index 0000000000000000000000000000000000000000..1fdf4447b6031ec251ec00138e33d4cbceb8a396 GIT binary patch literal 20 ZcmeAS@N?(olHy`uVBq!ia0vp^R{8911Ltkuhw`~gzT#ZI0f92^|CANoH4a>Ywr zBT7OtN^_H}tUPlQ(^IXi!ZTA!G8l{v4BkJ{X9g;fz*ORqnwg$a!eDG>80+!E?>`VA zsR<48WJt@*Nww0~*DuK}&@W5O$xP8J$V;!}?KuZDPY_9MaAs91gQc;VsR>jP**(4? znYpP9hQ<~~CPtPPCKg}hiw*(xD}eL|=ckpFCl;kLxcmA0x>{L*y^xofnd6q2T#{c@ zneP(%0H~C~)5S5QVouK<&&et$r>cE33pFkN9#ORRj8pCkrV9*Q4(0}XH$*SfES|}H zlKDRi|C9X>=emC~=W(rgs20<5c;>sr{sq#!B3#wFky9rMK75z9>X(?@73B#tj`{R= zrgXLMZm*tk>+<(~-)rw1huFHfw79qIc4lDQVQtLZFq5gGA(??eae>D-1|>DYCoB#H z^(+hw3z&QQ89#hGx&Gg~`XBHA?>=u|>pI2uQNa!Ut=DcnJKN*(Zr|0u$$Ko+(&poUZaIFUs>%;KS3mpYH#)9ss$3 B#a#dZ literal 0 HcmV?d00001 diff --git a/gio/tests/thumbnails/mtime-zero.png b/gio/tests/thumbnails/mtime-zero.png new file mode 100644 index 0000000000000000000000000000000000000000..8bac5f917d1bfa72c7181925efd02ff3a82d055b GIT binary patch literal 512 zcmeAS@N?(olHy`uVBq!ia0vp^R~Z->8911Ltkuhw`~gzT#ZI0f92^|CANoH4a>Ywr zBT7OtN^_H}tUPlQ(^IXi!ZTA!G8l{v4BkJ{X9g;fz*ORqnwg$a!eDG>80+!E52!{J zNlj>wCqr6hPO6o@zJ5t=fqrgDW^Sr(RccYbUO`@ZC2!9;pawo94Za~j1q=pXD{kX6CphCYR(FRpz^dJ^(6Z@N{tushHEV$8)mE z$*F4J%tB3zzeg0UJ>!(Sg6RSSmxH;%-VM>qG>d04pJe{e!vAFd!@2IC%z0cZ9;(H( z9G>|uv44RyuLxJQZsgR7f)C%Nt@#YP+Z{gjX_CG@Cl1UK|Kot!vf}>e#Q^qPOks=uKvgS z|GUrI*Sb!zeN=Emf9thd&(8L^yxVs>cVcBMABUgE)-dC4hcrJ;#)g%%t(m51&Yrod zFW-1`hrq-+n`a6Z8mFs#%8T;+6!`G;?Wg;Ht^Yr}{C?HH@c-BUf9vl5_wDlinoVn> Riq3hqM7rFm-F&mc1pxfq&dvY; literal 0 HcmV?d00001 diff --git a/gio/tests/thumbnails/no-text-data.png b/gio/tests/thumbnails/no-text-data.png new file mode 100644 index 0000000000000000000000000000000000000000..2eae44affdb5e17094d271f12d449bbdb18fcb7a GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^DL~xM!2~3mnO`~qDb50q$YKTt>GdGY7$-GR1}Mm0 z;_2(kewRyv%aD`5{)Yntg93x6i(^Q|t(4uT-=~}`eO?|XSor?znft3(?OL^~JI8L8 zf9H~vi&9;aJUo@Nj~VQdOc48aNPGRBuZQkcZM%1qn|WJ!+?h0n_iSuBylfNFzbuGj za1G2^HT&$lb?aWOTDR)H_UC)jg3lkinz6IZsdrF%oH8eW&S%T}&Hvxlf4^_6yiiz( zWnu!u%-!renmb%7*3aeS?47BRFPUijrcq-;G1KOG9(P0-EIE~S@80e1QlX*6*16;e E05V5pssI20 literal 0 HcmV?d00001 diff --git a/gio/tests/thumbnails/overlong-value.png b/gio/tests/thumbnails/overlong-value.png new file mode 100644 index 0000000000000000000000000000000000000000..0f3c56e32487f819c82d8aeeb599dc9539d74c99 GIT binary patch literal 512 zcmeAS@N?(olHy`uVBq!ia0vp^R~Z->8911Ltkuhw`~gzT#ZI0f92^|CANoH4a>Ywr zBT7OtN^_H}tUPlQ(^IXi!ZTA!G8l{v4BkJ{X9g;fz*ORqnwg$a!eDG>80+!E52!{B zNlj>wCqr6hPO6o@zJ5t=fqq$HPG*W;L0&q8kH4QgLnUv|IiLFSJ$pPStDKyw_RTERwD@~O(b_Xkxht41FmO4T8|>W> zy-c%sCi6+=|1A7Z_CK8K{>hxjwc?>#Ov~Y!?-KhLNb`ztRqIAhohbP5UD~Q&VsclM zC(JnJ)8CoW)xNvEdd98G-}im5y>A?1>*CVl-m=@7fpLemF>}LArizAS1_s3i9^V+0 z)C8ZfI26>gFfc4&?&)Xz@a^RKfA8vly#K%ZynU_f6x&AyH}tn&yY=jBkITD#w{s^} z#`1Cad29_c?siD?(`0N|Ioq0PistN@tNQYdH+Kk3oU?hRV4-ok%BQ?2&rg950T80S A!~g&Q literal 0 HcmV?d00001 diff --git a/gio/tests/thumbnails/uri-mismatch.png b/gio/tests/thumbnails/uri-mismatch.png new file mode 100644 index 0000000000000000000000000000000000000000..7629983a85dd7ba58329681713c90aba207047e9 GIT binary patch literal 512 zcmeAS@N?(olHy`uVBq!ia0vp^R~Z->8911Ltkuhw`~gzT#ZI0f92^|CANoH4a>Ywr zBT7OtN^_H}tUPlQ(^IXi!ZTA!G8l{v4BkJ{X9g;fz*ORqnwg$a!eDG>80+!E52!{1 zNlj>wCqr6hPO6o@zJ5t=fqq$HPG*X3UcPQ|W>uZC+w#j$2}KNq$jfzDwu>pi%}; z7srr_IX!zkC##&Cs`kw+)U^0}MA6zaPPr?XE--L8m>cZf5WP&Zcqa2n=Kn1GPxe2Y z>;B1{$F<_2T1?B~neP(&7fADpa8>I@PMs+D@Lk%fUt)4slqbwM=F{Jq($&7Zy?Vy2 z%is5Xuf1;^V(a44;@+~`nSpVKwJ~$UOs0y4WCjMs1s>lRl+*;Dus9UdvoJ6$VD9N> z{P6AM`hV~0f4u*{`@DUv>lE8Z1vm7!Uc2?|Y>&&keYbNbR>tyi_<3v%Gwyas^V4K( zSUKC8X^Q6TnXCHpjW>4)Oq{cMreL9Qy2_`#D9=xU4^Q8Iy8qYu|Fg^QSN#kBfBpZr P?*4z@F5j=&v?dAwp~cH- literal 0 HcmV?d00001 diff --git a/gio/tests/thumbnails/valid-no-size.png b/gio/tests/thumbnails/valid-no-size.png new file mode 100644 index 0000000000000000000000000000000000000000..7629983a85dd7ba58329681713c90aba207047e9 GIT binary patch literal 512 zcmeAS@N?(olHy`uVBq!ia0vp^R~Z->8911Ltkuhw`~gzT#ZI0f92^|CANoH4a>Ywr zBT7OtN^_H}tUPlQ(^IXi!ZTA!G8l{v4BkJ{X9g;fz*ORqnwg$a!eDG>80+!E52!{1 zNlj>wCqr6hPO6o@zJ5t=fqq$HPG*X3UcPQ|W>uZC+w#j$2}KNq$jfzDwu>pi%}; z7srr_IX!zkC##&Cs`kw+)U^0}MA6zaPPr?XE--L8m>cZf5WP&Zcqa2n=Kn1GPxe2Y z>;B1{$F<_2T1?B~neP(&7fADpa8>I@PMs+D@Lk%fUt)4slqbwM=F{Jq($&7Zy?Vy2 z%is5Xuf1;^V(a44;@+~`nSpVKwJ~$UOs0y4WCjMs1s>lRl+*;Dus9UdvoJ6$VD9N> z{P6AM`hV~0f4u*{`@DUv>lE8Z1vm7!Uc2?|Y>&&keYbNbR>tyi_<3v%Gwyas^V4K( zSUKC8X^Q6TnXCHpjW>4)Oq{cMreL9Qy2_`#D9=xU4^Q8Iy8qYu|Fg^QSN#kBfBpZr P?*4z@F5j=&v?dAwp~cH- literal 0 HcmV?d00001 diff --git a/gio/tests/thumbnails/valid.png b/gio/tests/thumbnails/valid.png new file mode 100644 index 0000000000000000000000000000000000000000..cc432082d0034439b1cda79274f431c91f38125c GIT binary patch literal 512 zcmeAS@N?(olHy`uVBq!ia0vp^R~Z->8911Ltkuhw`~gzT#ZI0f92^|CANoH4a>Ywr zBT7OtN^_H}tUPlQ(^IXi!ZTA!G8l{v4BkJ{X9g;fz*ORqnwg$a!eDG>80+!E52!`~ zNlj>wCqr6hPO6o@zJ5t=fqq$HPG*W;L0)<#Z_hcPT0tbW!I@R543@@brY2BHWcT=n zWag$a7#dp`nHX7Gm{@#~FFFLXD>y%`q&%@GmBHQ5-`Ca33hafv#LOJG#N?9vqRM=i z&<8+gF?hN-hE&Yy+2c7`<>XYgZ)TyU#or@})}C?7UBPsLfy=?%VDEAm)O5RnpcFYS~qg)M8Sve(pLQvle?lkVa73^{?3%H z_TBB(Gj3h}zVCbOed7>Y7nc_Imfg+_j61B2nHy#@RWu|sFeonY_{N~5CisNKp`f0H zfnfo2Pe0>_ZztFPdsqMC{r}zP?Q319*gh(_p}+Oot!HO@T;A=wojb8ImXE{FV{4dk zw?mqrCS$|O+15-`G-uCT)t7I)xkF&$oXs-@3ysrNKIKJuehPee`u5ZPzt#f)(geYQ literal 0 HcmV?d00001