[Devel,RHEL7,COMMIT] ms/packet: fix race condition in packet_set_ring

Submitted by Konstantin Khorenko on Dec. 6, 2016, 10:16 a.m.

Details

Message ID 201612061016.uB6AG472030932@finist_cl7.x64_64.work.ct
State New
Series "ms/packet: fix race condition in packet_set_ring"
Headers show

Commit Message

Konstantin Khorenko Dec. 6, 2016, 10:16 a.m.
The commit is pushed to "branch-rh7-3.10.0-327.36.1.vz7.20.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.36.1.vz7.20.11
------>
commit e8993d723121f3d9303db373849bcd01df2def48
Author: Philip Pettersson <philip.pettersson@gmail.com>
Date:   Wed Nov 30 14:55:36 2016 -0800

    ms/packet: fix race condition in packet_set_ring
    
    When packet_set_ring creates a ring buffer it will initialize a
    struct timer_list if the packet version is TPACKET_V3. This value
    can then be raced by a different thread calling setsockopt to
    set the version to TPACKET_V1 before packet_set_ring has finished.
    
    This leads to a use-after-free on a function pointer in the
    struct timer_list when the socket is closed as the previously
    initialized timer will not be deleted.
    
    The bug is fixed by taking lock_sock(sk) in packet_setsockopt when
    changing the packet version while also taking the lock at the start
    of packet_set_ring.
    
    Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.")
    Signed-off-by: Philip Pettersson <philip.pettersson@gmail.com>
    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    
    ============================================================
    CVE-2016-8655: Linux af_packet.c race condition (local root)
    
    Philip Pettersson discovered a race condition in the af_packet implementation
    in the Linux kernel. A local unprivileged attacker could use this to cause a
    denial of service (system crash) or run arbitrary code with administrative
    privileges.
    
    https://jira.sw.ru/browse/PSBM-56699
---
 net/packet/af_packet.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2a1b15a..0e662e3 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3313,19 +3313,25 @@  packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
 		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;
 		switch (val) {
 		case TPACKET_V1:
 		case TPACKET_V2:
 		case TPACKET_V3:
-			po->tp_version = val;
-			return 0;
+			break;
 		default:
 			return -EINVAL;
 		}
+		lock_sock(sk);
+		if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+			ret = -EBUSY;
+		} else {
+			po->tp_version = val;
+			ret = 0;
+		}
+		release_sock(sk);
+		return ret;
 	}
 	case PACKET_RESERVE:
 	{
@@ -3781,6 +3787,7 @@  static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 	/* Added to avoid minimal code churn */
 	struct tpacket_req *req = &req_u->req;
 
+	lock_sock(sk);
 	/* Opening a Tx-ring is NOT supported in TPACKET_V3 */
 	if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
 		WARN(1, "Tx-ring is not supported.\n");
@@ -3869,7 +3876,6 @@  static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 			goto out;
 	}
 
-	lock_sock(sk);
 
 	/* Detach socket from network */
 	spin_lock(&po->bind_lock);
@@ -3918,7 +3924,6 @@  static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 		if (!tx_ring)
 			prb_shutdown_retire_blk_timer(po, tx_ring, rb_queue);
 	}
-	release_sock(sk);
 
 	if (pg_vec) {
 		if (psc)
@@ -3927,6 +3932,7 @@  static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 		free_pg_vec(pg_vec, order, req->tp_block_nr);
 	}
 out:
+	release_sock(sk);
 	return err;
 }