Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

netfilter: xt_owner: no longer acquire sk_callback_lock in mt_owner()

After commit 983512f3a87f ("net: Drop the lock in skb_may_tx_timestamp()")
from Sebastian Andrzej Siewior, apply the same logic in mt_owner()
to avoid touching sk_callback_lock.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Florian Westphal <fw@strlen.de>

authored by

Eric Dumazet and committed by
Florian Westphal
cdec942a 5663ac3e

+14 -14
+14 -14
net/netfilter/xt_owner.c
··· 63 63 owner_mt(const struct sk_buff *skb, struct xt_action_param *par) 64 64 { 65 65 const struct xt_owner_match_info *info = par->matchinfo; 66 - const struct file *filp; 67 66 struct sock *sk = skb_to_full_sk(skb); 68 67 struct net *net = xt_net(par); 68 + const struct socket *sock; 69 + const struct file *filp; 69 70 70 - if (!sk || !sk->sk_socket || !net_eq(net, sock_net(sk))) 71 + if (!sk || !READ_ONCE(sk->sk_socket) || !net_eq(net, sock_net(sk))) 71 72 return (info->match ^ info->invert) == 0; 72 73 else if (info->match & info->invert & XT_OWNER_SOCKET) 73 74 /* ··· 77 76 */ 78 77 return false; 79 78 80 - read_lock_bh(&sk->sk_callback_lock); 81 - filp = sk->sk_socket ? sk->sk_socket->file : NULL; 82 - if (filp == NULL) { 83 - read_unlock_bh(&sk->sk_callback_lock); 79 + /* The sk pointer remains valid as long as the skb is. The sk_socket and 80 + * file pointer may become NULL if the socket is closed. Both structures 81 + * (including file->cred) are RCU freed which means they can be accessed 82 + * within a RCU read section. 83 + */ 84 + sock = READ_ONCE(sk->sk_socket); 85 + filp = sock ? READ_ONCE(sock->file) : NULL; 86 + if (filp == NULL) 84 87 return ((info->match ^ info->invert) & 85 88 (XT_OWNER_UID | XT_OWNER_GID)) == 0; 86 - } 87 89 88 90 if (info->match & XT_OWNER_UID) { 89 91 kuid_t uid_min = make_kuid(net->user_ns, info->uid_min); 90 92 kuid_t uid_max = make_kuid(net->user_ns, info->uid_max); 93 + 91 94 if ((uid_gte(filp->f_cred->fsuid, uid_min) && 92 95 uid_lte(filp->f_cred->fsuid, uid_max)) ^ 93 - !(info->invert & XT_OWNER_UID)) { 94 - read_unlock_bh(&sk->sk_callback_lock); 96 + !(info->invert & XT_OWNER_UID)) 95 97 return false; 96 - } 97 98 } 98 99 99 100 if (info->match & XT_OWNER_GID) { ··· 120 117 } 121 118 } 122 119 123 - if (match ^ !(info->invert & XT_OWNER_GID)) { 124 - read_unlock_bh(&sk->sk_callback_lock); 120 + if (match ^ !(info->invert & XT_OWNER_GID)) 125 121 return false; 126 - } 127 122 } 128 123 129 - read_unlock_bh(&sk->sk_callback_lock); 130 124 return true; 131 125 } 132 126