[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <87zfz32r6j.fsf@cloudflare.com>
Date: Fri, 24 Nov 2023 14:43:24 +0100
From: Jakub Sitnicki <jakub@...udflare.com>
To: Cong Wang <xiyou.wangcong@...il.com>
Cc: John Fastabend <john.fastabend@...il.com>, martin.lau@...nel.org,
bpf@...r.kernel.org, netdev@...r.kernel.org
Subject: Re: [PATCH bpf v2 1/2] bpf: sockmap, af_unix stream sockets need to
hold ref for pair sock
On Thu, Nov 23, 2023 at 12:24 PM -08, Cong Wang wrote:
> On Wed, Nov 22, 2023 at 11:24:51AM -0800, John Fastabend wrote:
>> AF_UNIX stream sockets are a paired socket. So sending on one of the pairs
>> will lookup the paired socket as part of the send operation. It is possible
>> however to put just one of the pairs in a BPF map. This currently
>> increments the refcnt on the sock in the sockmap to ensure it is not
>> free'd by the stack before sockmap cleans up its state and stops any
>> skbs being sent/recv'd to that socket.
>>
>> But we missed a case. If the peer socket is closed it will be
>> free'd by the stack. However, the paired socket can still be
>> referenced from BPF sockmap side because we hold a reference
>> there. Then if we are sending traffic through BPF sockmap to
>> that socket it will try to dereference the free'd pair in its
>> send logic creating a use after free. And following splat,
>
> Hmm, how could it pass the SOCK_DEAD test in unix_stream_sendmsg()?
>
> 2285 unix_state_lock(other);
> 2286
> 2287 if (sock_flag(other, SOCK_DEAD) ||
> 2288 (other->sk_shutdown & RCV_SHUTDOWN))
> 2289 goto pipe_err_free;
The quoted UAF happens after unix_state_unlock(other):
2285 unix_state_lock(other);
2286
2287 if (sock_flag(other, SOCK_DEAD) ||
2288 (other->sk_shutdown & RCV_SHUTDOWN))
2289 goto pipe_err_free;
2290
2291 maybe_add_creds(skb, sock, other);
2292 scm_stat_add(other, skb);
2293 skb_queue_tail(&other->sk_receive_queue, skb);
2294 unix_state_unlock(other);
2295 other->sk_data_ready(other); <-- UAF
Although, I think I saw it happen at unix_state_lock(other) as well.
We don't hold a ref on other, so we're racing with __sock_release /
unix_release_sock.
Powered by blists - more mailing lists