Bug 1096593 (CVE-2014-0209)

Summary: CVE-2014-0209 libXfont: integer overflow of allocations in font metadata file parsing
Product: [Other] Security Response Reporter: Huzaifa S. Sidhpurwala <huzaifas>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED ERRATA QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: unspecifiedCC: btissoir, carnil, jkurik, jrusnack, kem, security-response-team
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: libXfont 1.4.8, libXfont 1.4.99.901 (1.5.0rc1) Doc Type: Bug Fix
Doc Text:
A use-after-free flaw was found in the way libXfont processed certain font files when attempting to add a new directory to the font path. A malicious, local user could exploit this issue to potentially execute arbitrary code with the privileges of the X.Org server.
Story Points: ---
Clone Of: Environment:
Last Closed: 2014-11-25 07:46:41 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1097397, 1163601, 1163602, 1163603, 1163604, 1165521    
Bug Blocks: 1096603    

Description Huzaifa S. Sidhpurwala 2014-05-12 06:29:16 UTC
When a local user who is already authenticated to the X server adds a new directory to the font path, the X server calls libXfont to open the fonts.dir and fonts.alias files in that directory and add entries to the font tables for every line in it.  A large file (~2-4 gb) could cause the allocations to overflow, and allow the remaining data read from the file to overwrite other memory in the heap.

Affected functions: FontFileAddEntry(), lexAlias()


Acknowledgements:

Red Hat would like to thank the X.org project for reporting this issue. Upstream acknowledges Ilja van Sprundel as the original reporter of this issue.

Comment 2 Vincent Danen 2014-05-13 17:44:14 UTC
Created libXfont tracking bugs for this issue:

Affects: fedora-all [bug 1097397]

Comment 3 Vincent Danen 2014-05-27 18:11:05 UTC
Statement:

(none)

Comment 4 Fedora Update System 2014-07-16 02:01:06 UTC
libXfont-1.4.8-1.fc20 has been pushed to the Fedora 20 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 5 Fedora Update System 2014-07-23 03:01:28 UTC
libXfont-1.4.8-1.fc19 has been pushed to the Fedora 19 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 6 Huzaifa S. Sidhpurwala 2014-11-10 06:31:09 UTC
I decided to revisit this flaw after a long time and reading the commit message + patch it seems the issue may not really exists. 

"lexAlias() reads from a file in a loop. It does this by starting with a 64 byte buffer. If that size limit is hit, it does a realloc of the buffer size << 1, basically doubling the needed length every time the length limit is hit. Eventually, this will shift out to 0 (for a length of ~4gig), and that length will be passed on to realloc(). A length of 0 (with a valid pointer) causes realloc to free the buffer on most POSIX platforms, but the caller will still have a pointer to it, leading to use after free issues."

When realloc is passed zero via the size arguement, it actually frees the pointer and returns null. 

If you carefully look at the code, this output is checked via:

http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/fontfile/dirfile.c?id=05c8020a49416dd8b7510cbba45ce4f3fc81a7dc#n385

before actually using the pointer.

So when nbuf is null, the function bails out, i dont think an issue really exists here.

Comment 7 Tomas Hoger 2014-11-10 08:07:22 UTC
(In reply to Huzaifa S. Sidhpurwala from comment #6)
> When realloc is passed zero via the size arguement, it actually frees the
> pointer and returns null. 

I see both Linux and posix man pages say:

  If size was equal to 0, either NULL or a pointer suitable to be passed
  to free() is returned.

Glibc info pages do not seem to mention anything about the special size == 0 behavior.  Quick look at the code suggests glibc should guarantee NULL.

However, there's other thing you're missing.  Both tokenBuf and tokenSize are static.  Hence if you trigger the post-realloc if (!nbuf) check, tokenBuf will still contain non-NULL pointer to a chunk of memory that was freed in realloc(0), which should lead to use-after-free on the next lexAlias() call, afaics.

Comment 8 Huzaifa S. Sidhpurwala 2014-11-12 08:19:49 UTC
(In reply to Tomas Hoger from comment #7)

> However, there's other thing you're missing.  Both tokenBuf and tokenSize
> are static.  Hence if you trigger the post-realloc if (!nbuf) check,
> tokenBuf will still contain non-NULL pointer to a chunk of memory that was
> freed in realloc(0), which should lead to use-after-free on the next
> lexAlias() call, afaics.

There is no next lexAlias() call. When EALLOC is returned by lexAlias(). The calling function ReadFontAlias() breaks out of the loop at:

http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/fontfile/dirfile.c?id=05c8020a49416dd8b7510cbba45ce4f3fc81a7dc#n310

Closes the fontfile and bails out.

Comment 9 Tomas Hoger 2014-11-12 09:08:27 UTC
Is there a guarantee that ReadFontAlias() is not called against before process exist, e.g. for the next font file?

Comment 10 Tomas Hoger 2014-11-12 09:10:32 UTC
(In reply to Tomas Hoger from comment #9)
> Is there a guarantee that ReadFontAlias() is not called against before
> process exist, e.g. for the next font file?

... not called again before process exit ...

Comment 11 Huzaifa S. Sidhpurwala 2014-11-12 09:47:55 UTC
Here is the call path:

Catalogue* ()
|_ FontFileInitFPE()
    |_ FontFileReadDirectory()  -> Available to devels as an API to libXfont
        |_ ReadFontAlias()
             |_ lexAlias()


At each level during the call-path, the return value is checked and there is a provision to bail out, if its value is anything but "Successful".

FontFileReadDirectory() is available as an API to libXfont. It has a return value as well and developers using this function, should really check it.

I am going to ask the package maintainer to re-confirm. There is no value in sending this to upstream at the time.

Comment 12 Benjamin Tissoires 2014-11-12 15:29:08 UTC
[foreword, I just step up as libX* maintainer, so I may not be 100% accurate]

From what I can read in the code, without the CVE patch, this path is possible:

FontFileReadDirectory() is called first
|_ ReadFontAlias()
|  |_ lexAlias() -> EALLOC, tokenBuf freed but not NULL, and tokenSize != 0
|  |_ -> AllocError
|_ -> AllocError

A program can then call again FontFileReadDirectory():

FontFileReadDirectory()
|_ ReadFontAlias()
   |_ lexAlias(): count < tokenSize so we use the freed tokenBuf

So if a developer does not check the return value of FontFileReadDirectory(), or tries again (you never know, sometime it works the second attempt...), then the CVE is triggered.

Comment 15 Huzaifa S. Sidhpurwala 2014-11-17 04:49:31 UTC
Based on the analysis in comment #6 and others, it seems like arbitrary code execution with the permissions of the user running Xorg (root user) would indeed be possible in this case.

Because of which this issue was re-evaluated to have important security impact.

Comment 16 errata-xmlrpc 2014-11-18 11:42:10 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 6
  Red Hat Enterprise Linux 7

Via RHSA-2014:1870 https://rhn.redhat.com/errata/RHSA-2014-1870.html

Comment 18 Martin Prpič 2014-11-19 08:17:26 UTC
IssueDescription:

A use-after-free flaw was found in the way libXfont processed certain font files when attempting to add a new directory to the font path. A malicious, local user could exploit this issue to potentially execute arbitrary code with the privileges of the X.Org server.

Comment 19 errata-xmlrpc 2014-11-24 20:57:45 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 5

Via RHSA-2014:1893 https://rhn.redhat.com/errata/RHSA-2014-1893.html