mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
landlock: Fix unmarked concurrent access to socket family
Socket family is read (twice) in a context where the socket is not
locked, so another thread can setsockopt(IPV6_ADDRFORM) to write it
concurrently. Add needed READ_ONCE() annotation.
Use the proper macro to access __sk_common.skc_family like everywhere
else.
Fixes: fff69fb03d ("landlock: Support network rules with TCP bind and connect")
Signed-off-by: Matthieu Buffet <matthieu@buffet.re>
Link: https://patch.msgid.link/20260609211511.85630-1-matthieu@buffet.re
Link: https://patch.msgid.link/20260609211511.85630-2-matthieu@buffet.re
[mic: Squash two patches, move variable to ease backport, fix comment
formatting]
Signed-off-by: Mickaël Salaün <mic@digikod.net>
This commit is contained in:
parent
0302cd72fe
commit
0ce4243509
|
|
@ -46,6 +46,7 @@ static int current_check_access_socket(struct socket *const sock,
|
|||
const int addrlen,
|
||||
access_mask_t access_request)
|
||||
{
|
||||
unsigned short sock_family;
|
||||
__be16 port;
|
||||
struct layer_access_masks layer_masks = {};
|
||||
const struct landlock_rule *rule;
|
||||
|
|
@ -66,6 +67,12 @@ static int current_check_access_socket(struct socket *const sock,
|
|||
if (addrlen < offsetofend(typeof(*address), sa_family))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* The socket is not locked, so sk_family can change concurrently due to
|
||||
* e.g. setsockopt(IPV6_ADDRFORM).
|
||||
*/
|
||||
sock_family = READ_ONCE(sock->sk->sk_family);
|
||||
|
||||
switch (address->sa_family) {
|
||||
case AF_UNSPEC:
|
||||
if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
|
||||
|
|
@ -102,7 +109,7 @@ static int current_check_access_socket(struct socket *const sock,
|
|||
* these checks, but it is safer to return a proper
|
||||
* error and test consistency thanks to kselftest.
|
||||
*/
|
||||
if (sock->sk->__sk_common.skc_family == AF_INET) {
|
||||
if (sock_family == AF_INET) {
|
||||
const struct sockaddr_in *const sockaddr =
|
||||
(struct sockaddr_in *)address;
|
||||
|
||||
|
|
@ -180,7 +187,7 @@ static int current_check_access_socket(struct socket *const sock,
|
|||
* check, but it is safer to return a proper error and test
|
||||
* consistency thanks to kselftest.
|
||||
*/
|
||||
if (address->sa_family != sock->sk->__sk_common.skc_family &&
|
||||
if (address->sa_family != sock_family &&
|
||||
address->sa_family != AF_UNSPEC)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user