Commit 31c07dff authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski

net: nfc: fix races in nfc_llcp_sock_get() and nfc_llcp_sock_get_sn()

Sili Luo reported a race in nfc_llcp_sock_get(), leading to UAF.

Getting a reference on the socket found in a lookup while
holding a lock should happen before releasing the lock.

nfc_llcp_sock_get_sn() has a similar problem.

Finally nfc_llcp_recv_snl() needs to make sure the socket
found by nfc_llcp_sock_from_sn() does not disappear.

Fixes: 8f50020e ("NFC: LLCP late binding")
Reported-by: default avatarSili Luo <rootlab@huawei.com>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Willy Tarreau <w@1wt.eu>
Reviewed-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20231009123110.3735515-1-edumazet@google.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 5093bbfc
...@@ -203,17 +203,13 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, ...@@ -203,17 +203,13 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
if (tmp_sock->ssap == ssap && tmp_sock->dsap == dsap) { if (tmp_sock->ssap == ssap && tmp_sock->dsap == dsap) {
llcp_sock = tmp_sock; llcp_sock = tmp_sock;
sock_hold(&llcp_sock->sk);
break; break;
} }
} }
read_unlock(&local->sockets.lock); read_unlock(&local->sockets.lock);
if (llcp_sock == NULL)
return NULL;
sock_hold(&llcp_sock->sk);
return llcp_sock; return llcp_sock;
} }
...@@ -346,7 +342,8 @@ static int nfc_llcp_wks_sap(const char *service_name, size_t service_name_len) ...@@ -346,7 +342,8 @@ static int nfc_llcp_wks_sap(const char *service_name, size_t service_name_len)
static static
struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local, struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local,
const u8 *sn, size_t sn_len) const u8 *sn, size_t sn_len,
bool needref)
{ {
struct sock *sk; struct sock *sk;
struct nfc_llcp_sock *llcp_sock, *tmp_sock; struct nfc_llcp_sock *llcp_sock, *tmp_sock;
...@@ -382,6 +379,8 @@ struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local, ...@@ -382,6 +379,8 @@ struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local,
if (memcmp(sn, tmp_sock->service_name, sn_len) == 0) { if (memcmp(sn, tmp_sock->service_name, sn_len) == 0) {
llcp_sock = tmp_sock; llcp_sock = tmp_sock;
if (needref)
sock_hold(&llcp_sock->sk);
break; break;
} }
} }
...@@ -423,7 +422,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, ...@@ -423,7 +422,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
* to this service name. * to this service name.
*/ */
if (nfc_llcp_sock_from_sn(local, sock->service_name, if (nfc_llcp_sock_from_sn(local, sock->service_name,
sock->service_name_len) != NULL) { sock->service_name_len,
false) != NULL) {
mutex_unlock(&local->sdp_lock); mutex_unlock(&local->sdp_lock);
return LLCP_SAP_MAX; return LLCP_SAP_MAX;
...@@ -824,16 +824,7 @@ static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local ...@@ -824,16 +824,7 @@ static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local
static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local,
const u8 *sn, size_t sn_len) const u8 *sn, size_t sn_len)
{ {
struct nfc_llcp_sock *llcp_sock; return nfc_llcp_sock_from_sn(local, sn, sn_len, true);
llcp_sock = nfc_llcp_sock_from_sn(local, sn, sn_len);
if (llcp_sock == NULL)
return NULL;
sock_hold(&llcp_sock->sk);
return llcp_sock;
} }
static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len) static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len)
...@@ -1298,7 +1289,8 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, ...@@ -1298,7 +1289,8 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
} }
llcp_sock = nfc_llcp_sock_from_sn(local, service_name, llcp_sock = nfc_llcp_sock_from_sn(local, service_name,
service_name_len); service_name_len,
true);
if (!llcp_sock) { if (!llcp_sock) {
sap = 0; sap = 0;
goto add_snl; goto add_snl;
...@@ -1318,6 +1310,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, ...@@ -1318,6 +1310,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
if (sap == LLCP_SAP_MAX) { if (sap == LLCP_SAP_MAX) {
sap = 0; sap = 0;
nfc_llcp_sock_put(llcp_sock);
goto add_snl; goto add_snl;
} }
...@@ -1335,6 +1328,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, ...@@ -1335,6 +1328,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
pr_debug("%p %d\n", llcp_sock, sap); pr_debug("%p %d\n", llcp_sock, sap);
nfc_llcp_sock_put(llcp_sock);
add_snl: add_snl:
sdp = nfc_llcp_build_sdres_tlv(tid, sap); sdp = nfc_llcp_build_sdres_tlv(tid, sap);
if (sdp == NULL) if (sdp == NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment