Linux kernel: CVE-2017-2636: local privilege escalation flaw in n_hdlc

From: Alexander Popov <alex.popov@xxxxxxxxx>
To: oss-security@xxxxxxxxxxxxxxxxxx
Date: Tue, 7 Mar 2017 20:45:48 +0300
Hello!

This is an announcement of CVE-2017-2636, which is a race condition in
the n_hdlc Linux kernel driver (drivers/tty/n_hdlc.c). It can be exploited
to gain a local privilege escalation.

This driver provides HDLC serial line discipline and comes as a kernel module
in many Linux distributions, which have CONFIG_N_HDLC=m in the kernel config.

The bug was introduced on 22 June 2009:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=be10eb7589337e5defbe214dae038a53dd21add8

My fix to the Linux kernel mainline was proposed on 28 February 2017 and
should be available soon. Please see the attachment.

I will publish my PoC exploit later, giving people some time to update
their systems.

I've found this bug investigating a suspicious kernel crash made by syzkaller
(https://github.com/google/syzkaller).

-- Bug details --

N_HDLC line discipline uses a self-made singly linked lists for data
buffers and has n_hdlc.tbuf pointer for buffer retransmitting after
an error. If sending of a data buffer is not successful, then its
address is saved in n_hdlc.tbuf and the next time n_hdlc_send_frames()
will try to resend it first of all.

But the commit be10eb7589337e5defbe214dae038a53dd21add8 ("tty: n_hdlc add
buffer flushing") introduced racy access to n_hdlc.tbuf.

After transmission error concurrent flush_tx_queue() and n_hdlc_send_frames()
can put a buffer pointed by n_hdlc.tbuf to tx_free_buf_list twice. That
causes an exploitable double free error in n_hdlc_release().

To fix the issue I used a standard kernel linked list protected by a spinlock
and got rid of n_hdlc.tbuf. In case of transmission error the current data
buffer is put after the head of tx_buf_list.

--

Kernel updates are ready, please update your systems.

Best regards,
Alexander Popov
Positive Technologies
https://www.ptsecurity.com