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

Commit e1adea92 authored by Huw Davies's avatar Huw Davies Committed by Paul Moore
Browse files

calipso: Allow request sockets to be relabelled by the lsm.



Request sockets need to have a label that takes into account the
incoming connection as well as their parent's label.  This is used
for the outgoing SYN-ACK and for their child full-socket.

Signed-off-by: default avatarHuw Davies <huw@codeweavers.com>
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
parent 56ac42bc
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -229,6 +229,8 @@ struct netlbl_lsm_secattr {
 * @sock_getattr: retrieve the socket's attr
 * @sock_setattr: set the socket's attr
 * @sock_delattr: remove the socket's attr
 * @req_setattr: set the req socket's attr
 * @req_delattr: remove the req socket's attr
 *
 * Description:
 * This structure is filled out by the CALIPSO engine and passed
@@ -252,6 +254,10 @@ struct netlbl_calipso_ops {
			    const struct calipso_doi *doi_def,
			    const struct netlbl_lsm_secattr *secattr);
	void (*sock_delattr)(struct sock *sk);
	int (*req_setattr)(struct request_sock *req,
			   const struct calipso_doi *doi_def,
			   const struct netlbl_lsm_secattr *secattr);
	void (*req_delattr)(struct request_sock *req);
};

/*
+86 −0
Original line number Diff line number Diff line
@@ -889,6 +889,90 @@ static void calipso_sock_delattr(struct sock *sk)
	txopt_put(txopts);
}

/* request sock functions.
 */

/**
 * calipso_req_setattr - Add a CALIPSO option to a connection request socket
 * @req: the connection request socket
 * @doi_def: the CALIPSO DOI to use
 * @secattr: the specific security attributes of the socket
 *
 * Description:
 * Set the CALIPSO option on the given socket using the DOI definition and
 * security attributes passed to the function.  Returns zero on success and
 * negative values on failure.
 *
 */
static int calipso_req_setattr(struct request_sock *req,
			       const struct calipso_doi *doi_def,
			       const struct netlbl_lsm_secattr *secattr)
{
	struct ipv6_txoptions *txopts;
	struct inet_request_sock *req_inet = inet_rsk(req);
	struct ipv6_opt_hdr *old, *new;
	struct sock *sk = sk_to_full_sk(req_to_sk(req));

	if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
		old = req_inet->ipv6_opt->hopopt;
	else
		old = NULL;

	new = calipso_opt_insert(old, doi_def, secattr);
	if (IS_ERR(new))
		return PTR_ERR(new);

	txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
					 new, new ? ipv6_optlen(new) : 0);

	kfree(new);

	if (IS_ERR(txopts))
		return PTR_ERR(txopts);

	txopts = xchg(&req_inet->ipv6_opt, txopts);
	if (txopts) {
		atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
		txopt_put(txopts);
	}

	return 0;
}

/**
 * calipso_req_delattr - Delete the CALIPSO option from a request socket
 * @reg: the request socket
 *
 * Description:
 * Removes the CALIPSO option from a request socket, if present.
 *
 */
static void calipso_req_delattr(struct request_sock *req)
{
	struct inet_request_sock *req_inet = inet_rsk(req);
	struct ipv6_opt_hdr *new;
	struct ipv6_txoptions *txopts;
	struct sock *sk = sk_to_full_sk(req_to_sk(req));

	if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
		return;

	if (calipso_opt_del(req_inet->ipv6_opt->hopopt, &new))
		return; /* Nothing to do */

	txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
					 new, new ? ipv6_optlen(new) : 0);

	if (!IS_ERR(txopts)) {
		txopts = xchg(&req_inet->ipv6_opt, txopts);
		if (txopts) {
			atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
			txopt_put(txopts);
		}
	}
	kfree(new);
}

static const struct netlbl_calipso_ops ops = {
	.doi_add          = calipso_doi_add,
	.doi_free         = calipso_doi_free,
@@ -899,6 +983,8 @@ static const struct netlbl_calipso_ops ops = {
	.sock_getattr     = calipso_sock_getattr,
	.sock_setattr     = calipso_sock_setattr,
	.sock_delattr     = calipso_sock_delattr,
	.req_setattr      = calipso_req_setattr,
	.req_delattr      = calipso_req_delattr,
};

/**
+40 −0
Original line number Diff line number Diff line
@@ -578,3 +578,43 @@ void calipso_sock_delattr(struct sock *sk)
	if (ops)
		ops->sock_delattr(sk);
}

/**
 * calipso_req_setattr - Add a CALIPSO option to a connection request socket
 * @req: the connection request socket
 * @doi_def: the CALIPSO DOI to use
 * @secattr: the specific security attributes of the socket
 *
 * Description:
 * Set the CALIPSO option on the given socket using the DOI definition and
 * security attributes passed to the function.  Returns zero on success and
 * negative values on failure.
 *
 */
int calipso_req_setattr(struct request_sock *req,
			const struct calipso_doi *doi_def,
			const struct netlbl_lsm_secattr *secattr)
{
	int ret_val = -ENOMSG;
	const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();

	if (ops)
		ret_val = ops->req_setattr(req, doi_def, secattr);
	return ret_val;
}

/**
 * calipso_req_delattr - Delete the CALIPSO option from a request socket
 * @reg: the request socket
 *
 * Description:
 * Removes the CALIPSO option from a request socket, if present.
 *
 */
void calipso_req_delattr(struct request_sock *req)
{
	const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();

	if (ops)
		ops->req_delattr(req);
}
+4 −0
Original line number Diff line number Diff line
@@ -133,5 +133,9 @@ int calipso_sock_setattr(struct sock *sk,
			 const struct calipso_doi *doi_def,
			 const struct netlbl_lsm_secattr *secattr);
void calipso_sock_delattr(struct sock *sk);
int calipso_req_setattr(struct request_sock *req,
			const struct calipso_doi *doi_def,
			const struct netlbl_lsm_secattr *secattr);
void calipso_req_delattr(struct request_sock *req);

#endif
+26 −7
Original line number Diff line number Diff line
@@ -1053,12 +1053,13 @@ int netlbl_req_setattr(struct request_sock *req,
{
	int ret_val;
	struct netlbl_dommap_def *entry;
	struct inet_request_sock *ireq = inet_rsk(req);

	rcu_read_lock();
	switch (req->rsk_ops->family) {
	case AF_INET:
		entry = netlbl_domhsh_getentry_af4(secattr->domain,
						   inet_rsk(req)->ir_rmt_addr);
						   ireq->ir_rmt_addr);
		if (entry == NULL) {
			ret_val = -ENOENT;
			goto req_setattr_return;
@@ -1069,9 +1070,7 @@ int netlbl_req_setattr(struct request_sock *req,
						       entry->cipso, secattr);
			break;
		case NETLBL_NLTYPE_UNLABELED:
			/* just delete the protocols we support for right now
			 * but we could remove other protocols if needed */
			cipso_v4_req_delattr(req);
			netlbl_req_delattr(req);
			ret_val = 0;
			break;
		default:
@@ -1080,10 +1079,25 @@ int netlbl_req_setattr(struct request_sock *req,
		break;
#if IS_ENABLED(CONFIG_IPV6)
	case AF_INET6:
		/* since we don't support any IPv6 labeling protocols right
		 * now we can optimize everything away until we do */
		entry = netlbl_domhsh_getentry_af6(secattr->domain,
						   &ireq->ir_v6_rmt_addr);
		if (entry == NULL) {
			ret_val = -ENOENT;
			goto req_setattr_return;
		}
		switch (entry->type) {
		case NETLBL_NLTYPE_CALIPSO:
			ret_val = calipso_req_setattr(req,
						      entry->calipso, secattr);
			break;
		case NETLBL_NLTYPE_UNLABELED:
			netlbl_req_delattr(req);
			ret_val = 0;
			break;
		default:
			ret_val = -ENOENT;
		}
		break;
#endif /* IPv6 */
	default:
		ret_val = -EPROTONOSUPPORT;
@@ -1108,6 +1122,11 @@ void netlbl_req_delattr(struct request_sock *req)
	case AF_INET:
		cipso_v4_req_delattr(req);
		break;
#if IS_ENABLED(CONFIG_IPV6)
	case AF_INET6:
		calipso_req_delattr(req);
		break;
#endif /* IPv6 */
	}
}

Loading