Commit message: nfc: enforce CAP_NET_RAW for raw sockets

When creating a raw AF_NFC socket, CAP_NET_RAW needs to be checked
first.

Signed-off-by: Ori Nimron <orinimron123@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
CVE: CVE-2019-17056
CWE: CWE-276
Vulnerability description: llcp_sock_create in net/nfc/llcp_sock.c in the AF_NFC network module in the Linux kernel through 5.3.2 does not enforce CAP_NET_RAW, which means that unprivileged users can create a raw socket, aka CID-3a359798b176.

Project: linux

static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
	struct sock *sk = sock->sk;
	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
	struct nfc_llcp_local *local;
	struct nfc_dev *dev;
	struct sockaddr_nfc_llcp llcp_addr;
	int len, ret = 0;

	if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
	    addr->sa_family != AF_NFC)
		return -EINVAL;

	pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family);

	memset(&llcp_addr, 0, sizeof(llcp_addr));
	len = min_t(unsigned int, sizeof(llcp_addr), alen);
	memcpy(&llcp_addr, addr, len);

	/* This is going to be a listening socket, dsap must be 0 */
	if (llcp_addr.dsap != 0)
		return -EINVAL;

	lock_sock(sk);

	if (sk->sk_state != LLCP_CLOSED) {
		ret = -EBADFD;
		goto error;
	}

	dev = nfc_get_device(llcp_addr.dev_idx);
	if (dev == NULL) {
		ret = -ENODEV;
		goto error;
	}

	local = nfc_llcp_find_local(dev);
	if (local == NULL) {
		ret = -ENODEV;
		goto put_dev;
	}

	llcp_sock->dev = dev;
	llcp_sock->local = nfc_llcp_local_get(local);
	llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
	llcp_sock->service_name_len = min_t(unsigned int,
					    llcp_addr.service_name_len,
					    NFC_LLCP_MAX_SERVICE_NAME);
	llcp_sock->service_name = kmemdup(llcp_addr.service_name,
					  llcp_sock->service_name_len,
					  GFP_KERNEL);

	llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock);
	if (llcp_sock->ssap == LLCP_SAP_MAX) {
		ret = -EADDRINUSE;
		goto put_dev;
	}

	llcp_sock->reserved_ssap = llcp_sock->ssap;

	nfc_llcp_sock_link(&local->sockets, sk);

	pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap);

	sk->sk_state = LLCP_BOUND;

put_dev:
	nfc_put_device(dev);

error:
	release_sock(sk);
	return ret;
}

Project: linux

static __poll_t llcp_sock_poll(struct file *file, struct socket *sock,
				   poll_table *wait)
{
	struct sock *sk = sock->sk;
	__poll_t mask = 0;

	pr_debug("%p\n", sk);

	sock_poll_wait(file, sock, wait);

	if (sk->sk_state == LLCP_LISTEN)
		return llcp_accept_poll(sk);

	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
		mask |= EPOLLERR |
			(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0);

	if (!skb_queue_empty(&sk->sk_receive_queue))
		mask |= EPOLLIN | EPOLLRDNORM;

	if (sk->sk_state == LLCP_CLOSED)
		mask |= EPOLLHUP;

	if (sk->sk_shutdown & RCV_SHUTDOWN)
		mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM;

	if (sk->sk_shutdown == SHUTDOWN_MASK)
		mask |= EPOLLHUP;

	if (sock_writeable(sk) && sk->sk_state == LLCP_CONNECTED)
		mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
	else
		sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);

	pr_debug("mask 0x%x\n", mask);

	return mask;
}

Project: linux

static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
			     int len, int flags)
{
	struct sock *sk = sock->sk;
	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
	struct sockaddr_nfc_llcp *addr = (struct sockaddr_nfc_llcp *)_addr;
	struct nfc_dev *dev;
	struct nfc_llcp_local *local;
	int ret = 0;

	pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags);

	if (!addr || len < sizeof(*addr) || addr->sa_family != AF_NFC)
		return -EINVAL;

	if (addr->service_name_len == 0 && addr->dsap == 0)
		return -EINVAL;

	pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx,
		 addr->target_idx, addr->nfc_protocol);

	lock_sock(sk);

	if (sk->sk_state == LLCP_CONNECTED) {
		ret = -EISCONN;
		goto error;
	}

	dev = nfc_get_device(addr->dev_idx);
	if (dev == NULL) {
		ret = -ENODEV;
		goto error;
	}

	local = nfc_llcp_find_local(dev);
	if (local == NULL) {
		ret = -ENODEV;
		goto put_dev;
	}

	device_lock(&dev->dev);
	if (dev->dep_link_up == false) {
		ret = -ENOLINK;
		device_unlock(&dev->dev);
		goto put_dev;
	}
	device_unlock(&dev->dev);

	if (local->rf_mode == NFC_RF_INITIATOR &&
	    addr->target_idx != local->target_idx) {
		ret = -ENOLINK;
		goto put_dev;
	}

	llcp_sock->dev = dev;
	llcp_sock->local = nfc_llcp_local_get(local);
	llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
	if (llcp_sock->ssap == LLCP_SAP_MAX) {
		ret = -ENOMEM;
		goto put_dev;
	}

	llcp_sock->reserved_ssap = llcp_sock->ssap;

	if (addr->service_name_len == 0)
		llcp_sock->dsap = addr->dsap;
	else
		llcp_sock->dsap = LLCP_SAP_SDP;
	llcp_sock->nfc_protocol = addr->nfc_protocol;
	llcp_sock->service_name_len = min_t(unsigned int,
					    addr->service_name_len,
					    NFC_LLCP_MAX_SERVICE_NAME);
	llcp_sock->service_name = kmemdup(addr->service_name,
					  llcp_sock->service_name_len,
					  GFP_KERNEL);
	if (!llcp_sock->service_name) {
		ret = -ENOMEM;
		goto sock_llcp_release;
	}

	nfc_llcp_sock_link(&local->connecting_sockets, sk);

	ret = nfc_llcp_send_connect(llcp_sock);
	if (ret)
		goto sock_unlink;

	sk->sk_state = LLCP_CONNECTING;

	ret = sock_wait_state(sk, LLCP_CONNECTED,
			      sock_sndtimeo(sk, flags & O_NONBLOCK));
	if (ret && ret != -EINPROGRESS)
		goto sock_unlink;

	release_sock(sk);

	return ret;

sock_unlink:
	nfc_llcp_sock_unlink(&local->connecting_sockets, sk);

sock_llcp_release:
	nfc_llcp_put_ssap(local, llcp_sock->ssap);

put_dev:
	nfc_put_device(dev);

error:
	release_sock(sk);
	return ret;
}