From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Google-Smtp-Source: AB8JxZp0RNqq0bAcZmFZxMoApNLlG7O4dNQ78yK14RgIOhxUr6fYmaZabmHur/34nvemJ8Y2N3dh ARC-Seal: i=1; a=rsa-sha256; t=1524837949; cv=none; d=google.com; s=arc-20160816; b=i7EUJFw0WfO5z4D775TtR4s/utGz4lWZiXH+Bmrl8PKJFQBmVLk+NEs/JiwO+bonMc lQqv/NVnCF6JR0pTeFNRYWVm8Ja6BNfaiWyv99u1/uKzwHqSLp7a+J/IRW1itISDUbU0 DkCCcRRlTNqSezuLpDMSSRX9KpbKk+4GXICVrkDx6nFw7N+8QkgX1BLEPDWeHj/to1KB TyBos9VyyWexgf3p70er34Awp/HvmZ9Q4tmm9YdzcavuZoftjIDGEn/4N6IJKcGOJxXe G87wpeHu7CwodhIEGYIX4D/EkWEYiLrD2WuC6U27drcUmEhJDEwZNPGGmTef0deScIvb vcBQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=mime-version:user-agent:references:in-reply-to:message-id:date :subject:cc:to:from:dmarc-filter:arc-authentication-results; bh=Zj3mBJTN4b9ryLEMOd+A8hmYNcG0UU00TRXx9KWrPHY=; b=lDXsW/UEoHvrCpC0Hc7jKSQ6+S7jfXj1b2dOhBA7KuJoLQfoD6YIi/fV9yzH8pyXnJ SKa66pn5L/PP+2X3vkJwKbnxMc8IZDvhT8U1MKS3KG0r4zHruJ14SgGxMzqGG4i5okvg d0NOn+UTZ0fNNZN5ofgDrPloBW3QVPQGPcvc11e4X1DWw5MfsKxLG+cipCujH/CXWL5Q Etwa3nVOcSKjlMChKTzYvA/Fe15dzH0bt9vobthBkApwHAb5Yq+f3pQiN9RE098ub2TI gyEpFYXTiho7H03SyFYhQt9aPovgj2LCbereQtD7PfmCKt8IkNtLll/WbPDBmxp9++So ZIGA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of srs0=4/0d=hq=linuxfoundation.org=gregkh@kernel.org designates 198.145.29.99 as permitted sender) smtp.mailfrom=SRS0=4/0d=HQ=linuxfoundation.org=gregkh@kernel.org Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of srs0=4/0d=hq=linuxfoundation.org=gregkh@kernel.org designates 198.145.29.99 as permitted sender) smtp.mailfrom=SRS0=4/0d=HQ=linuxfoundation.org=gregkh@kernel.org DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C556B21890 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=linuxfoundation.org Authentication-Results: mail.kernel.org; spf=fail smtp.mailfrom=gregkh@linuxfoundation.org From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, DaeRyong Jeong , Byoungyoung Lee , Willem de Bruijn , "David S. Miller" Subject: [PATCH 4.9 55/74] packet: fix bitfield update race Date: Fri, 27 Apr 2018 15:58:45 +0200 Message-Id: <20180427135712.213928627@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180427135709.899303463@linuxfoundation.org> References: <20180427135709.899303463@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-LABELS: =?utf-8?b?IlxcU2VudCI=?= X-GMAIL-THRID: =?utf-8?q?1598908108463523673?= X-GMAIL-MSGID: =?utf-8?q?1598908478023327432?= X-Mailing-List: linux-kernel@vger.kernel.org List-ID: 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Willem de Bruijn [ Upstream commit a6361f0ca4b25460f2cdf3235ebe8115f622901e ] Updates to the bitfields in struct packet_sock are not atomic. Serialize these read-modify-write cycles. Move po->running into a separate variable. Its writes are protected by po->bind_lock (except for one startup case at packet_create). Also replace a textual precondition warning with lockdep annotation. All others are set only in packet_setsockopt. Serialize these updates by holding the socket lock. Analogous to other field updates, also hold the lock when testing whether a ring is active (pg_vec). Fixes: 8dc419447415 ("[PACKET]: Add optional checksum computation for recvmsg") Reported-by: DaeRyong Jeong Reported-by: Byoungyoung Lee Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 60 +++++++++++++++++++++++++++++++++++-------------- net/packet/internal.h | 10 ++++---- 2 files changed, 49 insertions(+), 21 deletions(-) --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -333,11 +333,11 @@ static void packet_pick_tx_queue(struct skb_set_queue_mapping(skb, queue_index); } -/* register_prot_hook must be invoked with the po->bind_lock held, +/* __register_prot_hook must be invoked through register_prot_hook * or from a context in which asynchronous accesses to the packet * socket is not possible (packet_create()). */ -static void register_prot_hook(struct sock *sk) +static void __register_prot_hook(struct sock *sk) { struct packet_sock *po = pkt_sk(sk); @@ -352,8 +352,13 @@ static void register_prot_hook(struct so } } -/* {,__}unregister_prot_hook() must be invoked with the po->bind_lock - * held. If the sync parameter is true, we will temporarily drop +static void register_prot_hook(struct sock *sk) +{ + lockdep_assert_held_once(&pkt_sk(sk)->bind_lock); + __register_prot_hook(sk); +} + +/* If the sync parameter is true, we will temporarily drop * the po->bind_lock and do a synchronize_net to make sure no * asynchronous packet processing paths still refer to the elements * of po->prot_hook. If the sync parameter is false, it is the @@ -363,6 +368,8 @@ static void __unregister_prot_hook(struc { struct packet_sock *po = pkt_sk(sk); + lockdep_assert_held_once(&po->bind_lock); + po->running = 0; if (po->fanout) @@ -3259,7 +3266,7 @@ static int packet_create(struct net *net if (proto) { po->prot_hook.type = proto; - register_prot_hook(sk); + __register_prot_hook(sk); } mutex_lock(&net->packet.sklist_lock); @@ -3735,12 +3742,18 @@ packet_setsockopt(struct socket *sock, i if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->tp_loss = !!val; - return 0; + + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_loss = !!val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_AUXDATA: { @@ -3751,7 +3764,9 @@ packet_setsockopt(struct socket *sock, i if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + lock_sock(sk); po->auxdata = !!val; + release_sock(sk); return 0; } case PACKET_ORIGDEV: @@ -3763,7 +3778,9 @@ packet_setsockopt(struct socket *sock, i if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + lock_sock(sk); po->origdev = !!val; + release_sock(sk); return 0; } case PACKET_VNET_HDR: @@ -3772,15 +3789,20 @@ packet_setsockopt(struct socket *sock, i if (sock->type != SOCK_RAW) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (optlen < sizeof(val)) return -EINVAL; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->has_vnet_hdr = !!val; - return 0; + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->has_vnet_hdr = !!val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_TIMESTAMP: { @@ -3818,11 +3840,17 @@ packet_setsockopt(struct socket *sock, i if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->tp_tx_has_off = !!val; + + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_tx_has_off = !!val; + ret = 0; + } + release_sock(sk); return 0; } case PACKET_QDISC_BYPASS: --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -109,10 +109,12 @@ struct packet_sock { int copy_thresh; spinlock_t bind_lock; struct mutex pg_vec_lock; - unsigned int running:1, /* prot_hook is attached*/ - auxdata:1, + unsigned int running; /* bind_lock must be held */ + unsigned int auxdata:1, /* writer must hold sock lock */ origdev:1, - has_vnet_hdr:1; + has_vnet_hdr:1, + tp_loss:1, + tp_tx_has_off:1; int pressure; int ifindex; /* bound device */ __be16 num; @@ -122,8 +124,6 @@ struct packet_sock { enum tpacket_versions tp_version; unsigned int tp_hdrlen; unsigned int tp_reserve; - unsigned int tp_loss:1; - unsigned int tp_tx_has_off:1; unsigned int tp_tstamp; struct net_device __rcu *cached_dev; int (*xmit)(struct sk_buff *skb);