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:
Matthieu Buffet 2026-06-09 23:15:10 +02:00 committed by Mickaël Salaün
parent 0302cd72fe
commit 0ce4243509
No known key found for this signature in database
GPG Key ID: E5E3D0E88C82F6D2

View File

@ -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;