Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3ac72c7 authored by Eric Dumazet's avatar Eric Dumazet Committed by Greg Kroah-Hartman
Browse files

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



[ Upstream commit ee5675ecdf7a4e713ed21d98a70c2871d6ebed01 ]

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>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 4760229b
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -2125,7 +2125,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
	sll = &PACKET_SKB_CB(skb)->sa.ll;
	sll->sll_hatype = dev->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;
	else
		sll->sll_ifindex = dev->ifindex;
@@ -2393,7 +2393,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
	sll->sll_hatype = dev->type;
	sll->sll_protocol = skb->protocol;
	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;
	else
		sll->sll_ifindex = dev->ifindex;
@@ -3853,9 +3853,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
		if (copy_from_user(&val, optval, sizeof(val)))
			return -EFAULT;

		lock_sock(sk);
		po->origdev = !!val;
		release_sock(sk);
		packet_sock_flag_set(po, PACKET_SOCK_ORIGDEV, val);
		return 0;
	}
	case PACKET_VNET_HDR:
@@ -4007,7 +4005,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
		val = po->auxdata;
		break;
	case PACKET_ORIGDEV:
		val = po->origdev;
		val = packet_sock_flag(po, PACKET_SOCK_ORIGDEV);
		break;
	case PACKET_VNET_HDR:
		val = po->has_vnet_hdr;
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ static int pdiag_put_info(const struct packet_sock *po, struct sk_buff *nlskb)
		pinfo.pdi_flags |= PDI_RUNNING;
	if (po->auxdata)
		pinfo.pdi_flags |= PDI_AUXDATA;
	if (po->origdev)
	if (packet_sock_flag(po, PACKET_SOCK_ORIGDEV))
		pinfo.pdi_flags |= PDI_ORIGDEV;
	if (po->has_vnet_hdr)
		pinfo.pdi_flags |= PDI_VNETHDR;
+21 −1
Original line number Diff line number Diff line
@@ -115,9 +115,9 @@ struct packet_sock {
	int			copy_thresh;
	spinlock_t		bind_lock;
	struct mutex		pg_vec_lock;
	unsigned long		flags;
	unsigned int		running;	/* bind_lock must be held */
	unsigned int		auxdata:1,	/* writer must hold sock lock */
				origdev:1,
				has_vnet_hdr:1,
				tp_loss:1,
				tp_tx_has_off:1;
@@ -143,4 +143,24 @@ static struct packet_sock *pkt_sk(struct 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