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

Commit af9eed5b authored by Phoebe Buckheister's avatar Phoebe Buckheister Committed by David S. Miller
Browse files

ieee802154: add dgram sockopts for security control



Allow datagram sockets to override the security settings of the device
they send from on a per-socket basis. Requires CAP_NET_ADMIN or
CAP_NET_RAW, since raw sockets can send arbitrary packets anyway.

Signed-off-by: default avatarPhoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f30be4d5
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -58,5 +58,13 @@ struct sockaddr_ieee802154 {
#define SOL_IEEE802154	0

#define WPAN_WANTACK		0
#define WPAN_SECURITY		1
#define WPAN_SECURITY_LEVEL	2

#define WPAN_SECURITY_DEFAULT	0
#define WPAN_SECURITY_OFF	1
#define WPAN_SECURITY_ON	2

#define WPAN_SECURITY_LEVEL_DEFAULT	(-1)

#endif
+66 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 */

#include <linux/capability.h>
#include <linux/net.h>
#include <linux/module.h>
#include <linux/if_arp.h>
@@ -47,6 +48,10 @@ struct dgram_sock {
	unsigned int bound:1;
	unsigned int connected:1;
	unsigned int want_ack:1;
	unsigned int secen:1;
	unsigned int secen_override:1;
	unsigned int seclevel:3;
	unsigned int seclevel_override:1;
};

static inline struct dgram_sock *dgram_sk(const struct sock *sk)
@@ -264,6 +269,11 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
		dst_addr = ro->dst_addr;
	}

	cb->secen = ro->secen;
	cb->secen_override = ro->secen_override;
	cb->seclevel = ro->seclevel;
	cb->seclevel_override = ro->seclevel_override;

	err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &dst_addr,
			      ro->bound ? &ro->src_addr : NULL, size);
	if (err < 0)
@@ -427,6 +437,20 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname,
	case WPAN_WANTACK:
		val = ro->want_ack;
		break;
	case WPAN_SECURITY:
		if (!ro->secen_override)
			val = WPAN_SECURITY_DEFAULT;
		else if (ro->secen)
			val = WPAN_SECURITY_ON;
		else
			val = WPAN_SECURITY_OFF;
		break;
	case WPAN_SECURITY_LEVEL:
		if (!ro->seclevel_override)
			val = WPAN_SECURITY_LEVEL_DEFAULT;
		else
			val = ro->seclevel;
		break;
	default:
		return -ENOPROTOOPT;
	}
@@ -442,6 +466,7 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname,
		    char __user *optval, unsigned int optlen)
{
	struct dgram_sock *ro = dgram_sk(sk);
	struct net *net = sock_net(sk);
	int val;
	int err = 0;

@@ -457,6 +482,47 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname,
	case WPAN_WANTACK:
		ro->want_ack = !!val;
		break;
	case WPAN_SECURITY:
		if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
		    !ns_capable(net->user_ns, CAP_NET_RAW)) {
			err = -EPERM;
			break;
		}

		switch (val) {
		case WPAN_SECURITY_DEFAULT:
			ro->secen_override = 0;
			break;
		case WPAN_SECURITY_ON:
			ro->secen_override = 1;
			ro->secen = 1;
			break;
		case WPAN_SECURITY_OFF:
			ro->secen_override = 1;
			ro->secen = 0;
			break;
		default:
			err = -EINVAL;
			break;
		}
		break;
	case WPAN_SECURITY_LEVEL:
		if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
		    !ns_capable(net->user_ns, CAP_NET_RAW)) {
			err = -EPERM;
			break;
		}

		if (val < WPAN_SECURITY_LEVEL_DEFAULT ||
		    val > IEEE802154_SCF_SECLEVEL_ENC_MIC128) {
			err = -EINVAL;
		} else if (val == WPAN_SECURITY_LEVEL_DEFAULT) {
			ro->seclevel_override = 0;
		} else {
			ro->seclevel_override = 1;
			ro->seclevel = val;
		}
		break;
	default:
		err = -ENOPROTOOPT;
		break;