nfc_llcp_getsockopt() read llcp_sock->local before lock_sock(sk) and
then dereferenced the cached pointer inside the locked region.
llcp_sock_bind() assigns and clears llcp_sock->local under the same
socket lock, dropping the last reference on its error path. A
getsockopt() racing an in-flight bind() can observe the pointer, block
on lock_sock(), and then dereference a freed nfc_llcp_local once bind()
has unwound.

Move the llcp_sock->local read and the NULL check inside the
lock_sock(sk) region so bind() cannot mutate or free the pointer between
the load and the use.

Fixes: 26fd76cab2e6 ("NFC: llcp: Implement socket options")
Signed-off-by: Breno Leitao <[email protected]>
---
 net/nfc/llcp_sock.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index aa9a78a671521..266590d402664 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -325,14 +325,16 @@ static int nfc_llcp_getsockopt(struct socket *sock, int 
level, int optname,
        if (len < sizeof(u32))
                return -EINVAL;
 
-       local = llcp_sock->local;
-       if (!local)
-               return -ENODEV;
-
        len = min_t(u32, len, sizeof(u32));
 
        lock_sock(sk);
 
+       local = llcp_sock->local;
+       if (!local) {
+               release_sock(sk);
+               return -ENODEV;
+       }
+
        switch (optname) {
        case NFC_LLCP_RW:
                rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;

-- 
2.53.0-Meta


Reply via email to