Bugzilla – Bug 554861
VUL-1: CVE-2009-3553: cups: use-after-free bug leads to remote denial of service
Last modified: 2016-04-15 10:56:25 UTC
Hi. There is a security bug in 'cups'. This information is from 'vendor-sec'. This bug is NOT PUBLIC. The coordinated release date (CRD) is: 2009-11-18 CVE number: CVE-2009-3553 CVE description: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3553 Original posting: @planned = yes ----- Forwarded message from Jan Lieskovsky <jlieskov@redhat.com> ----- Date: Wed, 11 Nov 2009 13:24:01 +0100 From: Jan Lieskovsky <jlieskov@redhat.com> User-Agent: Thunderbird 2.0.0.23 (X11/20090825) To: Vendor-Sec <vendor-sec@lst.de> Cc: Aaron Sigel <asigel@apple.com>, Mike Sweet <msweet@apple.com>, Tim Waugh <twaugh@redhat.com> Subject: [vendor-sec] CUPS STR #3200 issue (CVE-2009-3553) CRD = 2009-11-18 Errors-To: vendor-sec-admin@lst.de Hello vendors, pretty long time ago Opher reported CUPS DoS (cupsd crash), which can be performed from Win XP SP3 client - STR #3200: [1] http://www.cups.org/str.php?L3200 We further investigated the issue (reproduced) and Tim Waugh analyzed the reasons (see advisory) and provided patch (attached cups-1.3.10-CVE-2009-3553.patch, cups-1.4.2-CVE-2009-3553.patch). CVE identifier of CVE-2009-3553 has been already assigned to this issue. While the issue is meta-public, original ticket [1] suggests to provide more information and reference [1] in new ticket, so we would like to address this via coordinated CUPS release. Embargo date has been set up to Wednesday, 2009-11-18, 12:00 UTC time. Please let us know, if this doesn't suit for you for some reason. Thanks && Regards, Jan. -- Jan iankko Lieskovsky / Red Hat Security Response Team CUPS background: =============== The Common UNIX?? Printing System (CUPS) provides a portable printing layer for UNIX operating systems. CVE-2009-3553 flaw: =================== A pointer use-after-free flaw was found in the way CUPS used to handle references in its abstract file descriptors handling interface. Remote attacker could issue a specially- -crafted get-printer-jobs request, leading to denial of service (cupsd crash). Flaw analysis (by Tim Waugh): ============================= The CUPS scheduler uses an abstracted interface to handle select(), poll(), epoll() and kqueue for systems that support them, in ascending order of preference. The interface is simple, and the relevant parts are: * cupsdAddSelect, to add a particular file descriptor to the watch list, setting read/write callbacks and context * cupsdRemoveSelect, to remove a particular file descriptor from the watch list * cupsdDoSelect, to watch for changes and invoke callbacks as necessary The cupsdDoSelect() function uses whichever system method is best to watch for changes, and each time changes are discovered it loops through the watch list. For each file descriptor there are changes on: 1. the watch list item has its reference count incremented in order to prevent problems if the read callback calls cupsdRemoveSelect for this file descriptor 2. if there is data readable, the read callback is invoked 3. if there is data writable, the write callback is invoked 4. the reference count is decremented again Unfortunately this reference counting is not sufficient to prevent problems if the read callback calls cupsdRemoveSelect, and the reason is the context data that is set when cupsdAddSelect is called. Although the data in the watch list is protected (including the pointer to the context), the context *data* is not reference counted. In main.c, cupsdDoSelect() is used to handle client connections and the context is of type cupsd_client_t. When the read callback discovers that the connection has been closed by the remote host, the file descriptor is removed from the watch list using cupsdRemoveSelect, and the cupsd_client_t object is freed. If cupsdDoSelect() enters an iteration of its file descriptor loop hoping to call both the read and write callbacks, but the read callback closes the connection with cupsdCloseConnection, the write callback will attempt to reference freed memory, leading to undefined behaviour. A suggested fix for this is to avoid calling the write callback if cupsdRemoveSelect() function was called from the read callback. I have made a patch which does something similar by adding a 'changed' member to the watch list structure, setting it in cupsdAddSelect() and cupsdRemoveSelect(), clearing it before the read callback is called, and checking it afterwards. Affected CUPS versions: CUPS-1.3.* <= x <= CUPS-1.4.2 (latest) ====================== CVE identifier: CVE-2009-3553 has been assigned to this issue =============== CRD date: Wednesday, 2009-11-18, 12:00 UTC time ========= PoC: ==== Pretty complex - unable to reproduce the issue from Linux client. Requires Win XP SP3 client with Sun Java JDK-1.6.0-13 installed. Java Cups Test Jobs client: -------------------------- http://www.cups.org/strfiles/3200/Client.zip Scenario: -------- Server has 300 active printing jobs. Client issues Get-print-jobs request, thinks its incomplete, aborts and resend TCP RST. Impact: ------ CUPS-1.3.10 - clean crash (see attached debug && debug2 log). CUPS-1.3.11 - crash (but logs aren't so "beauty"). CUPS-1.4.2 - no record for cupsd crash in /var/log/messages, but cupsd just "is not running after exploitation." See also "raw_steps.txt" and sample textonly.ppd for elaborated list of steps. Patches: ======== Attached are patches against 1.3.10 and 1.4.2 versions of CUPS, provided by Tim Waugh. diff -up cups-1.3.10/scheduler/select.c.str3200 cups-1.3.10/scheduler/select.c --- cups-1.3.10/scheduler/select.c.str3200 2009-06-05 16:36:26.575877668 +0100 +++ cups-1.3.10/scheduler/select.c 2009-06-05 16:37:02.512752676 +0100 @@ -483,7 +483,7 @@ cupsdDoSelect(long timeout) /* I - Time (*(fdptr->read_cb))(fdptr->data); } - if (fdptr->write_cb && event->filter == EVFILT_WRITE) + if (fdptr->use > 1 && fdptr->write_cb && event->filter == EVFILT_WRITE) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", fdptr->fd); @@ -543,7 +543,7 @@ cupsdDoSelect(long timeout) /* I - Time (*(fdptr->read_cb))(fdptr->data); } - if (fdptr->write_cb && (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP))) + if (fdptr->use > 1 && fdptr->write_cb && (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP))) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", fdptr->fd); @@ -655,7 +655,7 @@ cupsdDoSelect(long timeout) /* I - Time (*(fdptr->read_cb))(fdptr->data); } - if (fdptr->write_cb && (pfd->revents & (POLLOUT | POLLERR | POLLHUP))) + if (fdptr->use > 1 && fdptr->write_cb && (pfd->revents & (POLLOUT | POLLERR | POLLHUP))) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", fdptr->fd); @@ -725,7 +725,7 @@ cupsdDoSelect(long timeout) /* I - Time (*(fdptr->read_cb))(fdptr->data); } - if (fdptr->write_cb && FD_ISSET(fdptr->fd, &cupsd_current_output)) + if (fdptr->use > 1 && fdptr->write_cb && FD_ISSET(fdptr->fd, &cupsd_current_output)) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...", fdptr->fd); diff -up cups-1.4.2/scheduler/select.c.str3200 cups-1.4.2/scheduler/select.c --- cups-1.4.2/scheduler/select.c.str3200 2009-07-15 00:07:52.000000000 +0100 +++ cups-1.4.2/scheduler/select.c 2009-11-10 15:42:55.359665174 +0000 @@ -454,7 +454,7 @@ cupsdDoSelect(long timeout) /* I - Time if (fdptr->read_cb && event->filter == EVFILT_READ) (*(fdptr->read_cb))(fdptr->data); - if (fdptr->write_cb && event->filter == EVFILT_WRITE) + if (fdptr->use > 1 && fdptr->write_cb && event->filter == EVFILT_WRITE) (*(fdptr->write_cb))(fdptr->data); release_fd(fdptr); @@ -499,7 +499,7 @@ cupsdDoSelect(long timeout) /* I - Time if (fdptr->read_cb && (event->events & (EPOLLIN | EPOLLERR | EPOLLHUP))) (*(fdptr->read_cb))(fdptr->data); - if (fdptr->write_cb && (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP))) + if (fdptr->use > 1 && fdptr->write_cb && (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP))) (*(fdptr->write_cb))(fdptr->data); release_fd(fdptr); @@ -590,7 +590,7 @@ cupsdDoSelect(long timeout) /* I - Time if (fdptr->read_cb && (pfd->revents & (POLLIN | POLLERR | POLLHUP))) (*(fdptr->read_cb))(fdptr->data); - if (fdptr->write_cb && (pfd->revents & (POLLOUT | POLLERR | POLLHUP))) + if (fdptr->use > 1 && fdptr->write_cb && (pfd->revents & (POLLOUT | POLLERR | POLLHUP))) (*(fdptr->write_cb))(fdptr->data); release_fd(fdptr); @@ -645,7 +645,7 @@ cupsdDoSelect(long timeout) /* I - Time if (fdptr->read_cb && FD_ISSET(fdptr->fd, &cupsd_current_input)) (*(fdptr->read_cb))(fdptr->data); - if (fdptr->write_cb && FD_ISSET(fdptr->fd, &cupsd_current_output)) + if (fdptr->use > 1 && fdptr->write_cb && FD_ISSET(fdptr->fd, &cupsd_current_output)) (*(fdptr->write_cb))(fdptr->data); release_fd(fdptr); Prerequisites: ============== a, Linux host with running cupsd 'serversHostname', 'serversIP' b, Windows client - 'clientsIP' - was using "en_windows_xp_home_with_service_pack_3_x86_cd_x14-82413" and - Java SE Development Kit 6u13 from: "https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=jdk-6u13-oth-JPR@CDS-CDS_Developer" (Selected "Windows x64" platform). CUPS Preparation phase: ====================== a, remove all cups related stuff from the system b, download and install cups wget http://ftp.easysw.com/pub/cups/1.3.10/cups-1.3.10-source.tar.gz tar xvzf cups-1.3.10-source.tar.gz cd cups-1.3.10 ./configure --prefix=/usr/local --enable-debug && make && make install c, configure cups: # modify cups to listen on 'serversIP' and allow connection from 'clientsIP' vi /usr/local/etc/cups/cupsd.conf LogLevel info | debug | debug2 # Only listen for connections from the local machine. Listen localhost:631 Listen serversHostname:631 ... # Restrict access to the server... <Location /> Allow From clientsIP Order allow,deny </Location> # add text-only printer to /usr/local/etc/cups/printers.conf See attached textonly.ppd, you will need to change the serversHostname in the: DeviceURI ipp://serversHostname/printers/my_printer row, other rows can be kept without change. # start cups and check if it recognizes 'test1' printer /etc/init.d/cups start /usr/local/bin/lpstat -v # schedule about 300 printing jobs head -1000 /usr/share/dict/words > /tmp/file.txt for i in `seq 1 300`; do /usr/local/bin/lp -d test1 /tmp/file.txt; done JAVA client preparation phase: ============================= # Install the SUN JDK 1.6.0_13 Java on Windows # Set the JAVA_HOME variable set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_13\bin (and potentially check via 'echo %JAVA_HOME%) # Download the malformed client and extract it wget http://www.cups.org/strfiles/3200/Client.zip unzip Client.zip && unzip cups-java-client-1.3.jar Attack scenario: ================ # Run the java client with 'serversIP' two times java TestCupsGetJobs serversIP (you should see something like: "Requested X bytes; Got: Y bytes. Partial string:" ). Then repeat the request till you get: "Connection refused:" (two times should be enough) Now check /var/log/messages for "*** glibc detected: /usr/local/sbin/cupsd: double free or corruption (top): address *** You can also check /usr/local/var/log/cups/error_log for full stack trace (in case 'debug2' log level was set up) # Printer configuration file for CUPS v1.3.10 <DefaultPrinter test1> Info Location DeviceURI ipp://serversHostname/printers/my_printer State Idle StateTime 1243606881 Accepting Yes Shared No JobSheets none none QuotaPeriod 0 PageLimit 0 KLimit 0 OpPolicy default ErrorPolicy stop-printer </Printer> ----- End forwarded message -----
I was already wondering where the weekly CUPS security issue is for this week... Comment #0 reads: "Affected CUPS versions: CUPS-1.3.* <= x <= CUPS-1.4.2" The command where_sources cups 2>/dev/null | egrep 'cups 1\.3|cups 1\.4' results the following maintained and affected distributions: cups-1.3.7 in 11.0 cups-1.3.9 in 11.1, sle11, sle11-moblin20 Strange that "where_sources" does not return 11.2 at all but we have cups-1.3.11 in 11.2 and in openSUSE:Factory I will fix it for now only for 11.0 and sle11. Please file a separated bug report for sle11-moblin20. I will fix it for 11.2 and openSUSE:Factory after the issue was published. By the way: I wonder why it is "critical"? Wouldn't be "major" sufficient for DOS so that we could use "critical" for really critical stuff like remote root exploits? Reasoning (only from my point of view of course): Usually a remote denial of service for CUPS is actually not such a terrible issue because nobody lets arbitrary users access his print server because in the end this results in access to the printer hardware. It is practically impossible to mitigate printer hardware access (and provide the users reasonable printing service nevertheless) by having whatever sophisticated print server in between because in the end the printer hardware processes data which is basically a program which controls the printer machine (also for non-PostScript printers). In particular any user who is allowed to print can always do DoS-like stuff, for example by sending this job to all print queues %!PS { } loop which will hang up any PostScript interpreter (Ghostscript or the printer's built-in interpreter). It is crucial to limit access to CUPS to trusted users (nobody wants to let random users print on his printers) and then DOS attacks are not such a big problem.
I am neither happy with a bug per week dropping down to us, that doesn't scale. Therefore I set the bug on the list of planned updates. Let's wait before you submit new packages, maybe there will be more issues appearing. where_source may not be adjusted for 11.2 maybe. Severity "Critical" is set automatically because of the close coordinated release date. I'll adjust it. BTW, was it possible to fix bug 542142 and bug 499735 with the latest security update. If so I can remove them from the planned update list.
I do not exactly understand what you ask in your "BTW" above. Bug #499735 was fixed by me for all distributions where it should fixed (SLE10-SP3 and SLE11-SP1), see https://bugzilla.novell.com/show_bug.cgi?id=499735#c47 Do you miss a distribution where it should also be fixed? Note that cups-backends is not a sub-package of cups, see https://bugzilla.novell.com/show_bug.cgi?id=499735#c49 In contrast Bug #542142 is not "my bug" because this one is about cups-autoconfig which is neither a sub-package of cups nor am I the cups-autoconfig package maintainer, see https://bugzilla.novell.com/show_bug.cgi?id=542142#c3 I like such main package names "foo-bar" very much where its first part "foo" is a different main package! Of course the opposite madness happens also: "gutenprint" is currently a sub-package of "cups-drivers" but its names do not indicate this - I will fix this when time permits for openSUSE 11.3, see https://bugzilla.novell.com/show_bug.cgi?id=514994#c7
Created attachment 327167 [details] cups-1.3.9-CVE-2009-3553.patch Submitted fixed cups-1.3.9 to SLE11/cups
Up to now I didn't test it at all. According to what comment #0 reads "Pretty complex - unable to reproduce the issue from Linux client. Requires Win XP SP3 client with Sun Java JDK-1.6.0-13 installed." I can neither reporoduce nor test it. As hopefully-best-effort attempt I will run the fixed cups-1.3.9 on my workstaiton for the next several days and see if I might detect whatever regression by chance but my workstation has of course not at all a real CUPS server printing load.
Submitted cups-1.3.9 fixed with attachment #327167 [details] to 11.1 There is a typo in comment #1: Wrong: "I will fix it for now only for 11.0 and sle11." Correct: "I will fix it for now only for 11.0, 11.1 and sle11."
Submitted cups-1.3.7 fixed with attachment #327167 [details] to 11.0 For now (i.e. as long as the issue in nut published) it is fixed but according to comment #5 I can neither reporoduce nor test it.
Reopening and reassigning to security-team for further processing. I would appreciate it if you could tell me when the issue was published so that I can then fix it also for 11.2 and openSUSE:Factory.
I run the fixed cups-1.3.9 on my workstation and basic printing seems to work as well as before: I can print locally on my HP LaserJet 1220 USB printer using various drivers (PostScript and several PCL drivers). I can print via our CUPS server print.suse.de on our network printers. The cupsd on my workstaiton can send Browsing info to a client host which can then print via the cupsd on my workstaiton on my HP LaserJet 1220 USB printer.
I wonder if the patch which is shown in comment #0 is really the full patch because Tim wrote there: "I have made a patch which does something similar by adding a 'changed' member to the watch list structure, setting it in cupsdAddSelect() and cupsdRemoveSelect(), clearing it before the read callback is called, and checking it afterwards." According to the patch which is shown in comment #0 and which I applied as attachment #327167 [details] it seems "fdptr->use" is this 'changed' member? If I am right, I do not understand the current patch because after it was applied I get only (long lines are wrapped only here): ----------------------------------------------------------------- find . | xargs grep 'fdptr->use' ./scheduler/select.c: fdptr->use = 1; ./scheduler/select.c: if (fdptr->use > 1 && fdptr->write_cb && event->filter == EVFILT_WRITE) ./scheduler/select.c: if (fdptr->use > 1 && fdptr->write_cb && (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP))) ./scheduler/select.c: if (fdptr->use > 1 && fdptr->write_cb && (pfd->revents & (POLLOUT | POLLERR | POLLHUP))) ./scheduler/select.c: if (fdptr->use > 1 && fdptr->write_cb && FD_ISSET(fdptr->fd, &cupsd_current_output)) ----------------------------------------------------------------- I do not understand how "fdptr->use > 1" might ever become true because as far as I see nothing imcrements it. Please check if the patch which is shown in comment #0 is really the full patch.
No need to hurry here. Just wait what will happen. Apple even wants to have a coordinated release date at the end of january 2010.
Should I remove what I already submitted to 11.0, 11.1 and SLE11 and for now only wait what will happen here? For now I reduced the bug priority to "P3 Medium" which does of course not mean that I do no longer care and of couse you can increase it whenever needed.
Yes, better remove it... especially when you say that the patch is not complete.
O.k. - I did right now rm -r /work/src/done/11.0/cups \ /work/src/done/11.1/cups \ /work/src/done/SLE11/cups
We can add the patch when its final to MaintenanceTracker-27896... but only if the coordinated release date isnt to far in the future.
Hello Johannes, Red Hat considers this issue public, so we can fix it together with MaintenanceTracker-27896. I'll ask QA to reject the patchinfos...
Thomas, do you have somewhere the complete patch or a public accessible URL to it? In particular I am not allowed to access http://www.cups.org/str.php?L3200 If you have somewhere the complete patch, could you attach it please.
Created attachment 328605 [details] cups-CVE-2009-3553.tgz
needinfo solved
They told me that the first patches are the final ones. I will attach a tar ball with all the attachments from the first mail. If this does not solve the problem you see, Johannes, let me know.
Sorry for causing confusion. In comment #10 I did only a quick "grep 'fdptr->use'" test but I didn't look carefully enough because actually there is already in scheduler/select.c: ------------------------------------------------------------ #define release_fd(f) { \ (f)->use --; \ if (!(f)->use) free((f));\ } #define retain_fd(f) (f)->use++ ------------------------------------------------------------ which do increment and decrement the "use" member so that the current patch looks correct now. Re-submitted to SLE11/cups Re-submitted to 11.1/cups Re-submitted to 11.0/cups Now "is_maintained -a cups" shows also 11.2 (compare comment #1). Therefore I would like to submit it now also to 11.2/cups but I cannot because /work/src/done/11.2/cups is owned by "root" and therefore "submitpac -X" cannot replace it but "submitpac" does also no longer submit it as cups-2009-11-24-11:18:38 (in contrast to what "submitpac -h" tells me) so that for 11.2 I just cannot submit it. Fixed for all affected distributions which are maintained by me and where I can submit it. The fix is still missing for 11.2 and openSUSE:Factory.
Reopening and reassigning to security-team for further processing.
Thanks.
(In reply to comment #21) > The fix is still missing for 11.2 and openSUSE:Factory. Could you use a submit request?
Meanwhile I can after my pending submit requests 24137 and 24139 for the other bug #548317 were accepted and comitted to make sure that I get the actually right sources when I check them out from openSUSE:11.2 and openSUSE:Factory...
i submitted a patchinfo for 11.0 and 11.1 with just the 1 cve
Johannes, the SLES 10 fixes were missing?
cups 1.1 ie sle10 is not listed as affected in the announcement, will cancel patchinfo.
Update released for: cups, cups-client, cups-client-debuginfo, cups-debuginfo, cups-debugsource, cups-devel, cups-libs, cups-libs-debuginfo Products: openSUSE 11.2 (debug, i586, x86_64)
JFYI, this bug was considered as planned update. Since there is no other update for sle11 we'd not bother QA just for this issue. I've copied the sle11 submission to sle11sp1 so the fix gets included on sp1. If we have to release a cups update for sle11 itself in the future we can merge back the sp1 version.
Submitted to openSUSE:11.2: $ osc request list openSUSE:11.2 cups 26592 State:new Creator:jsmeix When:2009-12-15T13:44:16 submit: home:jsmeix:branches:openSUSE:11.2:Update/cups -> openSUSE:11.2 Comment: 'fixed CVE-2009-3553 bnc#554861'
FYI: I got the sources via "osc branch openSUSE:11.2 cups" therefore I submitted it accordingly also to openSUSE:11.2 via "osc submitreq ..." and not to openSUSE:11.2:Update wherefrom "osc branch openSUSE:11.2 cups" actually took the sources.
Submitted to openSUSE:Factory $ osc request list openSUSE:Factory cups 26600 State:new Creator:jsmeix When:2009-12-15T14:16:27 submit: Printing/cups -> openSUSE:Factory Comment: 'fixed CVE-2009-3553 bnc#554861
For verification and testing by QA (compare comment #5 and comment #9): Right now I noticed CUPS STR #3454 http://www.cups.org/str.php?L3454 which provides a "good reproduction script that nicely demonstrates the issue": http://www.cups.org/strfiles/3454/crash-cups.pl For the script to work a printer named "PDF" should exist and be printable over IPP. I didn't test the script up to now.
the select code above does not exist in sles9 (also not in sles10). so sles9 is not affected.
Update released for: cups, cups-client, cups-debuginfo, cups-debugsource, cups-devel, cups-libs Products: openSUSE 11.0 (debug, i386, ppc, ppc64, x86_64) openSUSE 11.1 (debug, i586, ppc, ppc64, x86_64)
Update released for: cups, cups-client, cups-devel, cups-libs Products: Novell-Linux-Desktop 9 (i386, x86_64) Novell-Linux-POS 9 (i386) Open-Enterprise-Server 9 (i386) SUSE-CORE 9 (i386, ia64, ppc, s390, s390x, x86_64)
all released
there is still a suvbmission in 11.2/cups needs to be released too
close as fixed as it's superseded by 578215
This is an autogenerated message for OBS integration: This bug (554861) was mentioned in https://build.opensuse.org/request/show/26592 11.2 / cups https://build.opensuse.org/request/show/26600 Factory / cups