Commit ee5675ec authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net/packet: convert po->origdev to an atomic flag

syzbot/KCAN reported that po->origdev can be read
while another thread is changing its value.

We can avoid this splat by converting this field
to an actual bit.

Following patches will convert remaining 1bit fields.

Fixes: 80feaacb ("[AF_PACKET]: Add option to return orig_dev to userspace.")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarsyzbot <syzkaller@googlegroups.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b9d83ab8
...@@ -2184,7 +2184,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -2184,7 +2184,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
sll = &PACKET_SKB_CB(skb)->sa.ll; sll = &PACKET_SKB_CB(skb)->sa.ll;
sll->sll_hatype = dev->type; sll->sll_hatype = dev->type;
sll->sll_pkttype = skb->pkt_type; sll->sll_pkttype = skb->pkt_type;
if (unlikely(po->origdev)) if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV)))
sll->sll_ifindex = orig_dev->ifindex; sll->sll_ifindex = orig_dev->ifindex;
else else
sll->sll_ifindex = dev->ifindex; sll->sll_ifindex = dev->ifindex;
...@@ -2461,7 +2461,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -2461,7 +2461,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
sll->sll_hatype = dev->type; sll->sll_hatype = dev->type;
sll->sll_protocol = skb->protocol; sll->sll_protocol = skb->protocol;
sll->sll_pkttype = skb->pkt_type; sll->sll_pkttype = skb->pkt_type;
if (unlikely(po->origdev)) if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV)))
sll->sll_ifindex = orig_dev->ifindex; sll->sll_ifindex = orig_dev->ifindex;
else else
sll->sll_ifindex = dev->ifindex; sll->sll_ifindex = dev->ifindex;
...@@ -3914,9 +3914,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, ...@@ -3914,9 +3914,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
if (copy_from_sockptr(&val, optval, sizeof(val))) if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT; return -EFAULT;
lock_sock(sk); packet_sock_flag_set(po, PACKET_SOCK_ORIGDEV, val);
po->origdev = !!val;
release_sock(sk);
return 0; return 0;
} }
case PACKET_VNET_HDR: case PACKET_VNET_HDR:
...@@ -4065,7 +4063,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, ...@@ -4065,7 +4063,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
val = po->auxdata; val = po->auxdata;
break; break;
case PACKET_ORIGDEV: case PACKET_ORIGDEV:
val = po->origdev; val = packet_sock_flag(po, PACKET_SOCK_ORIGDEV);
break; break;
case PACKET_VNET_HDR: case PACKET_VNET_HDR:
val = po->has_vnet_hdr; val = po->has_vnet_hdr;
......
...@@ -25,7 +25,7 @@ static int pdiag_put_info(const struct packet_sock *po, struct sk_buff *nlskb) ...@@ -25,7 +25,7 @@ static int pdiag_put_info(const struct packet_sock *po, struct sk_buff *nlskb)
pinfo.pdi_flags |= PDI_RUNNING; pinfo.pdi_flags |= PDI_RUNNING;
if (po->auxdata) if (po->auxdata)
pinfo.pdi_flags |= PDI_AUXDATA; pinfo.pdi_flags |= PDI_AUXDATA;
if (po->origdev) if (packet_sock_flag(po, PACKET_SOCK_ORIGDEV))
pinfo.pdi_flags |= PDI_ORIGDEV; pinfo.pdi_flags |= PDI_ORIGDEV;
if (po->has_vnet_hdr) if (po->has_vnet_hdr)
pinfo.pdi_flags |= PDI_VNETHDR; pinfo.pdi_flags |= PDI_VNETHDR;
......
...@@ -116,9 +116,9 @@ struct packet_sock { ...@@ -116,9 +116,9 @@ struct packet_sock {
int copy_thresh; int copy_thresh;
spinlock_t bind_lock; spinlock_t bind_lock;
struct mutex pg_vec_lock; struct mutex pg_vec_lock;
unsigned long flags;
unsigned int running; /* bind_lock must be held */ unsigned int running; /* bind_lock must be held */
unsigned int auxdata:1, /* writer must hold sock lock */ unsigned int auxdata:1, /* writer must hold sock lock */
origdev:1,
has_vnet_hdr:1, has_vnet_hdr:1,
tp_loss:1, tp_loss:1,
tp_tx_has_off:1; tp_tx_has_off:1;
...@@ -144,4 +144,24 @@ static inline struct packet_sock *pkt_sk(struct sock *sk) ...@@ -144,4 +144,24 @@ static inline struct packet_sock *pkt_sk(struct sock *sk)
return (struct packet_sock *)sk; return (struct packet_sock *)sk;
} }
enum packet_sock_flags {
PACKET_SOCK_ORIGDEV,
};
static inline void packet_sock_flag_set(struct packet_sock *po,
enum packet_sock_flags flag,
bool val)
{
if (val)
set_bit(flag, &po->flags);
else
clear_bit(flag, &po->flags);
}
static inline bool packet_sock_flag(const struct packet_sock *po,
enum packet_sock_flags flag)
{
return test_bit(flag, &po->flags);
}
#endif #endif
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