-
Notifications
You must be signed in to change notification settings - Fork 464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remote DoS attack against cupsd via invalid username and malicious D-Bus library #5143
Comments
As expected building CUPS without DBUS support I think in particular on remotely accessible CUPS server machines In CUPS without DBUS support there is no longer I assume CUPS DBUS support is probably not needed For printing on the local host via the local cupsd |
Sigh... Why do library developers insist on using abort()? Doing so prevents applications and other libraries from cleaning up after themselves, saving state, etc. Anyways, the premise here is that you need to create a user account with an invalid name - root access required, of course - which then potentially allows a remote attacker to crash cupsd by exploiting a flaw in DBUS? @jsmeix I need to know where in cupsd we are calling the dbus function to cause this abort to happen. The only place I see this function getting called directly is when adding the job owner to a DBUS-based notification, but that won't happen unless you have a DBUS subscription active... |
I meant anyone who can become root on a remote host We (i.e. SUSE) learned about it via a customer report My blind guess is that the customer's remote host But in the end this does not matter because anyone |
I still need to know where the crash is happening in cupsd to have any chance of fixing or working around this bug in DBUS (and yes, using abort() in a library is a bug IMHO). |
I think next week I can try to provide details where exactly Below is a poposal how such kind of issues I fully agree it is a bug in a library when a library call On the other hand getting a signal from within a library call EPIPE fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also receive a SIGPIPE signal. (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.) How to deal with it is also documented in cups/api-filter.shtml As far as I remember some time ago cupsd had died Because signals can happen at any time from anywhere Perhaps the more general solution could be Perhaps it could make sense to protect cupsd As far as I see on first glance in the CUPS 2.2.5 code Simply put: |
Correction regarding There are some signals that indicate something went |
Unbelievable! /** * Aborts the program with SIGABRT (dumping core). */ void _dbus_abort (void) { const char *s; _dbus_print_backtrace (); s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT"); if (s && *s) { /* don't use _dbus_warn here since it can _dbus_abort() */ fprintf (stderr, " Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ()); _dbus_sleep_milliseconds (1000 * 180); } abort (); _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */ } It seems they even implemented double protection From my current point of view this indicates that For home user desktop systems perhaps via |
@jsmeix While technically SIGABRT can be caught (and often is in debuggers), since code that calls abort() is typically not designed to function after the call it will probably have worse effects so it isn't really safe. And as you notice in this case DBUS exits anyways. SIGPIPE is a little different since the interface is well-defined and well-used. And on some platforms there are even ways to disable SIGPIPE on a per-fd basis (which CUPS uses, when available). The original intent of abort() is to allow a developer to stop a process under exceptional circumstances ("this should never happen") when there is no other reasonable response. Calling it when an application supplied an invalid UTF-8 string is just wrong, and the API in question should have been designed to return an error code (not just a boolean success/fail) so it is possible to discover the reason for the failure without a crash report or some other logging to a questionable file descriptor (i.e. stderr is often mapped to /dev/null in server processes). As for whether DBUS is suitable for servers, they (the DBUS developers) market it as such and it is used widely in Linux to provide system services, so they need to fix this behavior. I've marked this as a security issue with high priority (not critical since it requires creation of an account with an invalid username) and will continue to investigate things on my end. |
@michaelrsweet For example with CUPS 2.2.5 on the client system normal_user@client$ cat print-job-invalid-user.test # Print a test page using print-job { # The name of the test... NAME "Print file using Print-Job" # The operation to use OPERATION Print-Job # Attributes, starting in the operation group... GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name "binär" ATTR mimeMediaType document-format "text/plain" GROUP job-attributes-tag ATTR integer copies 1 FILE "/etc/issue" # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes # What attributes do we expect? EXPECT job-id EXPECT job-uri } normal_user@client$ diff -U0 /usr/share/cups/ipptool/print-job.test print-job-invalid-user.test --- /usr/share/cups/ipptool/print-job.test 2017-10-18 13:03:33.000000000 +0200 +++ print-job-invalid-user.test 2017-10-23 11:12:41.249751001 +0200 @@ -14,2 +14,2 @@ - ATTR name requesting-user-name $user - ATTR mimeMediaType document-format $filetype + ATTR name requesting-user-name "binär" + ATTR mimeMediaType document-format "text/plain" @@ -20 +20 @@ - FILE $filename + FILE "/etc/issue" normal_user@client$ ipptool ipp://CUPS.server/printers/queue print-job-invalid-user.test Operation now in progress This aborts the cupsd running on CUPS.server. The crucial difference in print-job-invalid-user.test ATTR name requesting-user-name "binär" where the ISO-8859-1 encoded username "binär" 62 69 6e e4 72 i.e. same as in my initial |
@michaelrsweet I am really not an expert in this area but according to what I read As far as I see this would be the only way how a caller could FWIW: |
I added cupsdLogMessage(CUPSD_LOG_DEBUG2, "dbus_message_iter_append ..."); before all dbus_message_iter_append_* calls that I found. With that I got for a job with invalid username D [23/Oct/2017:13:37:06 +0200] [Job 8459] Applying default options... D [23/Oct/2017:13:37:06 +0200] add_job: requesting-user-name="binär" I [23/Oct/2017:13:37:06 +0200] [Job 8459] Adding start banner page "none". d [23/Oct/2017:13:37:06 +0200] copy_banner(con=0x556772d63db0[2], job=0x556772d4a220[8459], name="none") d [23/Oct/2017:13:37:06 +0200] cupsdAddEvent(event=job-created, dest=0x556772c8f520(tofile), job=0x556772d4a220(8459), text="Job created.", ...) d [23/Oct/2017:13:37:06 +0200] dbus_message_iter_append_string -> dbus_message_iter_append_basic subscriptions 11 d [23/Oct/2017:13:37:06 +0200] dbus_message_iter_append_uint32 -> dbus_message_iter_append_basic subscriptions 12 d [23/Oct/2017:13:37:06 +0200] dbus_message_iter_append_string -> dbus_message_iter_append_basic subscriptions 13 which matches (as expected) in my code in scheduler/subscriptions.c if (job) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "dbus_message_iter_append_uint32 -> dbus_message_iter_append_basic subscriptions 12"); dbus_message_iter_append_uint32(&iter, job->id); cupsdLogMessage(CUPSD_LOG_DEBUG2, "dbus_message_iter_append_string -> dbus_message_iter_append_basic subscriptions 13"); dbus_message_iter_append_string(&iter, job->username); } FYI: |
- scheduler/ipp.c: Make sure requesting-user-name string is valid UTF-8.
With the change in scheduler/ipp.c from binär@client:~> echo test | lp -h cups.server -d queue -t test lp: Bad requesting-user-name value: "requesting-user-name": Bad name value "binär" - bad UTF-8 sequence (RFC 8011 section 5.1.3). and when I use 'ipptool' as in user@host:~> ipptool ipp://localhost/printers/queue print-job-invalid-user.test Bad requesting-user-name value: "requesting-user-name": Bad name value "binär" - bad UTF-8 sequence (RFC 8011 section 5.1.3). and on the CUPS server I get in /var/log/cups/error_log (excerpts): d [24/Oct/2017:13:53:58 +0200] cupsdProcessIPPRequest: requesting-user-name nameWithoutLanguage 'binär' ... D [24/Oct/2017:13:53:58 +0200] Create-Job client-error-attributes-or-values-not-supported: Bad requesting-user-name value: \"requesting-user-name\": Bad name value \"binär\" - bad UTF-8 sequence (RFC 8011 section 5.1.3). E [24/Oct/2017:13:53:58 +0200] [Client 1] Returning IPP client-error-attributes-or-values-not-supported for Create-Job (ipp://localhost:631/printers/tofile) from 10.160.65.205 and d [24/Oct/2017:13:55:27 +0200] cupsdProcessIPPRequest: requesting-user-name nameWithoutLanguage 'binär' ... D [24/Oct/2017:13:55:27 +0200] Print-Job client-error-attributes-or-values-not-supported: Bad requesting-user-name value: \"requesting-user-name\": Bad name value \"binär\" - bad UTF-8 sequence (RFC 8011 section 5.1.3). E [24/Oct/2017:13:55:27 +0200] [Client 3] Returning IPP client-error-attributes-or-values-not-supported for Print-Job (ipp://localhost:631/printers/tofile) from localhost Accordingly from my point of view this particular issue Many thanks for the fix! |
FYI: There I had only looked at the source code but The configure script in the dbus-1.10.20 sources $ ./configure --help | grep assert --enable-asserts include assertion checks which seems via "configure --disable-asserts" one can make This way perhaps a D-Bus library could be made Also what is told on The low-level libdbus reference implementation ... It should be noted that the low-level implementation is not primarily designed for application authors to use. Rather, it is a basis for binding authors and a reference for reimplementations. indicates that "just compile" the low-level libdbus Accordingly it seems the root cause is not in the actual |
This has been assigned CVE-2017-18248. |
Also see Issue #5186 which applies this change more widely, to prevent similar attacks... (both this and the referenced issue will be in the forthcoming 2.2.7 release) |
Any user who can submit a print job to a CUPS server
can abort the cupsd running on the CUPS server by
submitting a job as a user with an invalid username.
I tested it with CUPS 1.7.5 and also the newest 2.2.5
so that I assume the issue is old and not fixed.
I think this issue here has the same root cause as
#4748
As far as I see the fix there belongs to the LPD mini daemon
but this issue here belongs to the cupsd.
How to reproduce:
On a (Linux) client system create a user with an
invalid username - I use 'binär' as username that has
the character ä (Latin small letter a with diaeresis,
i.e. the German a-umlaut) encoded in ISO-8859-1
encoding so that the username in hex byte values is
Usually one cannot create such a username with "useradd"
(because it rejects invalid usernames) so that one must
manually edit /etc/passwd.
Then as this user submit a print job from the client system
to a (possibly remote) CUPS server.
The cupsd on the CUPS server will bet aborted
inside a D-Bus library call that sends SIGABRT
which aborts the whole caller process.
In /var/log/messages or nowadays in the "journalctl" output
one gets things like
or
The text was updated successfully, but these errors were encountered: