gnu: fontconfig: Fix CVE-2016-5384.
* gnu/packages/fontutils.scm (fontconfig)[replacement]: New field. (fontconfig/fixed): New variable. * gnu/packages/patches/fontconfig-CVE-2016-5384.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it.
This commit is contained in:
		
							parent
							
								
									ed6ba9cc7b
								
							
						
					
					
						commit
						6b5e654dd4
					
				
					 3 changed files with 179 additions and 0 deletions
				
			
		| 
						 | 
					@ -505,6 +505,7 @@ dist_patch_DATA =						\
 | 
				
			||||||
  %D%/packages/patches/flint-ldconfig.patch			\
 | 
					  %D%/packages/patches/flint-ldconfig.patch			\
 | 
				
			||||||
  %D%/packages/patches/fltk-shared-lib-defines.patch		\
 | 
					  %D%/packages/patches/fltk-shared-lib-defines.patch		\
 | 
				
			||||||
  %D%/packages/patches/fltk-xfont-on-demand.patch		\
 | 
					  %D%/packages/patches/fltk-xfont-on-demand.patch		\
 | 
				
			||||||
 | 
					  %D%/packages/patches/fontconfig-CVE-2016-5384.patch		\
 | 
				
			||||||
  %D%/packages/patches/fontforge-svg-modtime.patch		\
 | 
					  %D%/packages/patches/fontforge-svg-modtime.patch		\
 | 
				
			||||||
  %D%/packages/patches/fossil-test-fixes.patch			\
 | 
					  %D%/packages/patches/fossil-test-fixes.patch			\
 | 
				
			||||||
  %D%/packages/patches/freeimage-CVE-2015-0852.patch		\
 | 
					  %D%/packages/patches/freeimage-CVE-2015-0852.patch		\
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,6 +223,7 @@ fonts to/from the WOFF2 format.")
 | 
				
			||||||
(define-public fontconfig
 | 
					(define-public fontconfig
 | 
				
			||||||
  (package
 | 
					  (package
 | 
				
			||||||
   (name "fontconfig")
 | 
					   (name "fontconfig")
 | 
				
			||||||
 | 
					   (replacement fontconfig/fixed)
 | 
				
			||||||
   (version "2.11.94")
 | 
					   (version "2.11.94")
 | 
				
			||||||
   (source (origin
 | 
					   (source (origin
 | 
				
			||||||
            (method url-fetch)
 | 
					            (method url-fetch)
 | 
				
			||||||
| 
						 | 
					@ -275,6 +276,13 @@ high quality, anti-aliased and subpixel rendered text on a display.")
 | 
				
			||||||
                       "See COPYING in the distribution."))
 | 
					                       "See COPYING in the distribution."))
 | 
				
			||||||
   (home-page "http://www.freedesktop.org/wiki/Software/fontconfig")))
 | 
					   (home-page "http://www.freedesktop.org/wiki/Software/fontconfig")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define fontconfig/fixed
 | 
				
			||||||
 | 
					  (package
 | 
				
			||||||
 | 
					    (inherit fontconfig)
 | 
				
			||||||
 | 
					    (source (origin
 | 
				
			||||||
 | 
					              (inherit (package-source fontconfig))
 | 
				
			||||||
 | 
					              (patches (search-patches "fontconfig-CVE-2016-5384.patch"))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(define-public t1lib
 | 
					(define-public t1lib
 | 
				
			||||||
  (package
 | 
					  (package
 | 
				
			||||||
   (name "t1lib")
 | 
					   (name "t1lib")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										170
									
								
								gnu/packages/patches/fontconfig-CVE-2016-5384.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								gnu/packages/patches/fontconfig-CVE-2016-5384.patch
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,170 @@
 | 
				
			||||||
 | 
					Fix CVE-2016-5384 (double-free resulting in arbitrary code execution):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5384>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copied from upstream code repository:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<https://cgit.freedesktop.org/fontconfig/commit/?id=7a4a5bd7897d216f0794ca9dbce0a4a5c9d14940>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					From 7a4a5bd7897d216f0794ca9dbce0a4a5c9d14940 Mon Sep 17 00:00:00 2001
 | 
				
			||||||
 | 
					From: Tobias Stoeckmann <tobias@stoeckmann.org>
 | 
				
			||||||
 | 
					Date: Sat, 25 Jun 2016 19:18:53 +0200
 | 
				
			||||||
 | 
					Subject: Properly validate offsets in cache files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The cache files are insufficiently validated. Even though the magic
 | 
				
			||||||
 | 
					number at the beginning of the file as well as time stamps are checked,
 | 
				
			||||||
 | 
					it is not verified if contained offsets are in legal ranges or are
 | 
				
			||||||
 | 
					even pointers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The lack of validation allows an attacker to trigger arbitrary free()
 | 
				
			||||||
 | 
					calls, which in turn allows double free attacks and therefore arbitrary
 | 
				
			||||||
 | 
					code execution. Due to the conversion from offsets into pointers through
 | 
				
			||||||
 | 
					macros, this even allows to circumvent ASLR protections.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This attack vector allows privilege escalation when used with setuid
 | 
				
			||||||
 | 
					binaries like fbterm. A user can create ~/.fonts or any other
 | 
				
			||||||
 | 
					system-defined user-private font directory, run fc-cache and adjust
 | 
				
			||||||
 | 
					cache files in ~/.cache/fontconfig. The execution of setuid binaries will
 | 
				
			||||||
 | 
					scan these files and therefore are prone to attacks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If it's not about code execution, an endless loop can be created by
 | 
				
			||||||
 | 
					letting linked lists become circular linked lists.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This patch verifies that:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The file is not larger than the maximum addressable space, which
 | 
				
			||||||
 | 
					  basically only affects 32 bit systems. This allows out of boundary
 | 
				
			||||||
 | 
					  access into unallocated memory.
 | 
				
			||||||
 | 
					- Offsets are always positive or zero
 | 
				
			||||||
 | 
					- Offsets do not point outside file boundaries
 | 
				
			||||||
 | 
					- No pointers are allowed in cache files, every "pointer or offset"
 | 
				
			||||||
 | 
					  field must be an offset or NULL
 | 
				
			||||||
 | 
					- Iterating linked lists must not take longer than the amount of elements
 | 
				
			||||||
 | 
					  specified. A violation of this rule can break a possible endless loop.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If one or more of these points are violated, the cache is recreated.
 | 
				
			||||||
 | 
					This is current behaviour.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Even though this patch fixes many issues, the use of mmap() shall be
 | 
				
			||||||
 | 
					forbidden in setuid binaries. It is impossible to guarantee with these
 | 
				
			||||||
 | 
					checks that a malicious user does not change cache files after
 | 
				
			||||||
 | 
					verification. This should be handled in a different patch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					diff --git a/src/fccache.c b/src/fccache.c
 | 
				
			||||||
 | 
					index 71e8f03..02ec301 100644
 | 
				
			||||||
 | 
					--- a/src/fccache.c
 | 
				
			||||||
 | 
					+++ b/src/fccache.c
 | 
				
			||||||
 | 
					@@ -27,6 +27,7 @@
 | 
				
			||||||
 | 
					 #include <fcntl.h>
 | 
				
			||||||
 | 
					 #include <dirent.h>
 | 
				
			||||||
 | 
					 #include <string.h>
 | 
				
			||||||
 | 
					+#include <limits.h>
 | 
				
			||||||
 | 
					 #include <sys/types.h>
 | 
				
			||||||
 | 
					 #include <sys/stat.h>
 | 
				
			||||||
 | 
					 #include <assert.h>
 | 
				
			||||||
 | 
					@@ -587,6 +588,82 @@ FcCacheTimeValid (FcConfig *config, FcCache *cache, struct stat *dir_stat)
 | 
				
			||||||
 | 
					     return cache->checksum == (int) dir_stat->st_mtime && fnano;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					+static FcBool
 | 
				
			||||||
 | 
					+FcCacheOffsetsValid (FcCache *cache)
 | 
				
			||||||
 | 
					+{
 | 
				
			||||||
 | 
					+    char		*base = (char *)cache;
 | 
				
			||||||
 | 
					+    char		*end = base + cache->size;
 | 
				
			||||||
 | 
					+    intptr_t		*dirs;
 | 
				
			||||||
 | 
					+    FcFontSet		*fs;
 | 
				
			||||||
 | 
					+    int			 i, j;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    if (cache->dir < 0 || cache->dir > cache->size - sizeof (intptr_t) ||
 | 
				
			||||||
 | 
					+        memchr (base + cache->dir, '\0', cache->size - cache->dir) == NULL)
 | 
				
			||||||
 | 
					+        return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    if (cache->dirs < 0 || cache->dirs >= cache->size ||
 | 
				
			||||||
 | 
					+        cache->dirs_count < 0 ||
 | 
				
			||||||
 | 
					+        cache->dirs_count > (cache->size - cache->dirs) / sizeof (intptr_t))
 | 
				
			||||||
 | 
					+        return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    dirs = FcCacheDirs (cache);
 | 
				
			||||||
 | 
					+    if (dirs)
 | 
				
			||||||
 | 
					+    {
 | 
				
			||||||
 | 
					+        for (i = 0; i < cache->dirs_count; i++)
 | 
				
			||||||
 | 
					+        {
 | 
				
			||||||
 | 
					+            FcChar8	*dir;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+            if (dirs[i] < 0 ||
 | 
				
			||||||
 | 
					+                dirs[i] > end - (char *) dirs - sizeof (intptr_t))
 | 
				
			||||||
 | 
					+                return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+            dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
 | 
				
			||||||
 | 
					+            if (memchr (dir, '\0', end - (char *) dir) == NULL)
 | 
				
			||||||
 | 
					+                return FcFalse;
 | 
				
			||||||
 | 
					+         }
 | 
				
			||||||
 | 
					+    }
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    if (cache->set < 0 || cache->set > cache->size - sizeof (FcFontSet))
 | 
				
			||||||
 | 
					+        return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    fs = FcCacheSet (cache);
 | 
				
			||||||
 | 
					+    if (fs)
 | 
				
			||||||
 | 
					+    {
 | 
				
			||||||
 | 
					+        if (fs->nfont > (end - (char *) fs) / sizeof (FcPattern))
 | 
				
			||||||
 | 
					+            return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        if (fs->fonts != 0 && !FcIsEncodedOffset(fs->fonts))
 | 
				
			||||||
 | 
					+            return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        for (i = 0; i < fs->nfont; i++)
 | 
				
			||||||
 | 
					+        {
 | 
				
			||||||
 | 
					+            FcPattern		*font = FcFontSetFont (fs, i);
 | 
				
			||||||
 | 
					+            FcPatternElt	*e;
 | 
				
			||||||
 | 
					+            FcValueListPtr	 l;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+            if ((char *) font < base ||
 | 
				
			||||||
 | 
					+                (char *) font > end - sizeof (FcFontSet) ||
 | 
				
			||||||
 | 
					+                font->elts_offset < 0 ||
 | 
				
			||||||
 | 
					+                font->elts_offset > end - (char *) font ||
 | 
				
			||||||
 | 
					+                font->num > (end - (char *) font - font->elts_offset) / sizeof (FcPatternElt))
 | 
				
			||||||
 | 
					+                return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+            e = FcPatternElts(font);
 | 
				
			||||||
 | 
					+            if (e->values != 0 && !FcIsEncodedOffset(e->values))
 | 
				
			||||||
 | 
					+                return FcFalse;
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+            for (j = font->num, l = FcPatternEltValues(e); j >= 0 && l; j--, l = FcValueListNext(l))
 | 
				
			||||||
 | 
					+                if (l->next != NULL && !FcIsEncodedOffset(l->next))
 | 
				
			||||||
 | 
					+                    break;
 | 
				
			||||||
 | 
					+            if (j < 0)
 | 
				
			||||||
 | 
					+                return FcFalse;
 | 
				
			||||||
 | 
					+        }
 | 
				
			||||||
 | 
					+    }
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    return FcTrue;
 | 
				
			||||||
 | 
					+}
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					 /*
 | 
				
			||||||
 | 
					  * Map a cache file into memory
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					@@ -596,7 +673,8 @@ FcDirCacheMapFd (FcConfig *config, int fd, struct stat *fd_stat, struct stat *di
 | 
				
			||||||
 | 
					     FcCache	*cache;
 | 
				
			||||||
 | 
					     FcBool	allocated = FcFalse;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					-    if (fd_stat->st_size < (int) sizeof (FcCache))
 | 
				
			||||||
 | 
					+    if (fd_stat->st_size > INTPTR_MAX ||
 | 
				
			||||||
 | 
					+        fd_stat->st_size < (int) sizeof (FcCache))
 | 
				
			||||||
 | 
					 	return NULL;
 | 
				
			||||||
 | 
					     cache = FcCacheFindByStat (fd_stat);
 | 
				
			||||||
 | 
					     if (cache)
 | 
				
			||||||
 | 
					@@ -652,6 +730,7 @@ FcDirCacheMapFd (FcConfig *config, int fd, struct stat *fd_stat, struct stat *di
 | 
				
			||||||
 | 
					     if (cache->magic != FC_CACHE_MAGIC_MMAP ||
 | 
				
			||||||
 | 
					 	cache->version < FC_CACHE_VERSION_NUMBER ||
 | 
				
			||||||
 | 
					 	cache->size != (intptr_t) fd_stat->st_size ||
 | 
				
			||||||
 | 
					+        !FcCacheOffsetsValid (cache) ||
 | 
				
			||||||
 | 
					 	!FcCacheTimeValid (config, cache, dir_stat) ||
 | 
				
			||||||
 | 
					 	!FcCacheInsert (cache, fd_stat))
 | 
				
			||||||
 | 
					     {
 | 
				
			||||||
 | 
					-- 
 | 
				
			||||||
 | 
					cgit v0.10.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in a new issue