[RFC PATCH 8/8] rxrpc: Set call security params in sendmsg() cmsg

David Howells dhowells at redhat.com
Thu Jun 23 06:29:46 PDT 2022


Allow a call's security parameters to be overridden from the socket
defaults by placing appropriate control messages in control message buffer.

Signed-off-by: David Howells <dhowells at redhat.com>
---

 include/uapi/linux/rxrpc.h |    2 ++
 net/rxrpc/af_rxrpc.c       |    2 +-
 net/rxrpc/ar-internal.h    |    6 +++++-
 net/rxrpc/key.c            |   26 ++++++++++++++++++++++++--
 net/rxrpc/sendmsg.c        |   39 +++++++++++++++++++++++++++++++++++----
 5 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/include/uapi/linux/rxrpc.h b/include/uapi/linux/rxrpc.h
index b4bbaa809b78..2e1a05b83be7 100644
--- a/include/uapi/linux/rxrpc.h
+++ b/include/uapi/linux/rxrpc.h
@@ -59,6 +59,8 @@ enum rxrpc_cmsg_type {
 	RXRPC_TX_LENGTH		= 12,	/* s-: Total length of Tx data */
 	RXRPC_SET_CALL_TIMEOUT	= 13,	/* s-: Set one or more call timeouts */
 	RXRPC_CHARGE_ACCEPT	= 14,	/* s-: Charge the accept pool with a user call ID */
+	RXRPC_SET_SECURITY_KEY	= 15,	/* s-: Set the security key description for the call */
+	RXRPC_SET_SECURITY_LEVEL = 16,	/* s-: Set the security level for the call */
 	RXRPC__SUPPORTED
 };
 
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index bf2bb1b99890..8b7e8ad6e020 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -920,7 +920,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
 			ret = -EISCONN;
 			if (rx->sk.sk_state != RXRPC_UNBOUND)
 				goto error;
-			ret = rxrpc_request_key(rx, optval, optlen);
+			ret = rxrpc_set_key(rx, optval, optlen);
 			goto error;
 
 		case RXRPC_SECURITY_KEYRING:
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 526169effe89..b80a9136e978 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -777,6 +777,9 @@ struct rxrpc_send_params {
 	enum rxrpc_command	command : 8;	/* The command to implement */
 	bool			exclusive;	/* Shared or exclusive call */
 	bool			upgrade;	/* If the connection is upgradeable */
+	unsigned int		sec_level;	/* Security level */
+	unsigned int		key_desc_len;
+	char			*key_desc;	/* Description of key to use (or NULL) */
 };
 
 #include <trace/events/rxrpc.h>
@@ -950,7 +953,8 @@ extern const struct rxrpc_security rxrpc_no_security;
  */
 extern struct key_type key_type_rxrpc;
 
-int rxrpc_request_key(struct rxrpc_sock *, sockptr_t , int);
+struct key *rxrpc_request_key(struct rxrpc_sock *, const char *, int);
+int rxrpc_set_key(struct rxrpc_sock *, const sockptr_t, int);
 int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time64_t,
 			      u32);
 
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index bbb270a01810..4ab1ec62ad2f 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -443,9 +443,31 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
 }
 
 /*
- * grab the security key for a socket
+ * Look up a security key
  */
-int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
+struct key *rxrpc_request_key(struct rxrpc_sock *rx, const char *name, int len)
+{
+	struct key *key;
+	char *description;
+
+	_enter("");
+
+	if (len <= 0 || len > PAGE_SIZE - 1)
+		return ERR_PTR(-EINVAL);
+
+	description = kmemdup_nul(name, len, GFP_KERNEL);
+	if (IS_ERR(description))
+		return ERR_PTR(-ENOMEM);
+
+	key = request_key_net(&key_type_rxrpc, description, sock_net(&rx->sk), NULL);
+	kfree(description);
+	return key;
+}
+
+/*
+ * Set the security key for a socket
+ */
+int rxrpc_set_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
 {
 	struct key *key;
 	char *description;
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 77699008c428..9153baf33635 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -560,6 +560,19 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)
 				return -ERANGE;
 			break;
 
+		case RXRPC_SET_SECURITY_KEY:
+			p->key_desc = CMSG_DATA(cmsg);
+			p->key_desc_len = len;
+			break;
+
+		case RXRPC_SET_SECURITY_LEVEL:
+			if (len != sizeof(p->sec_level))
+				return -EINVAL;
+			memcpy(&p->sec_level, CMSG_DATA(cmsg), sizeof(p->sec_level));
+			if (p->sec_level > RXRPC_SECURITY_ENCRYPT)
+				return -EINVAL;
+			break;
+
 		default:
 			return -EINVAL;
 		}
@@ -587,6 +600,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
 	struct rxrpc_conn_parameters cp;
 	struct rxrpc_call *call;
 	struct key *key;
+	bool put_key = false;
 
 	DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, msg->msg_name);
 
@@ -597,14 +611,27 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
 		return ERR_PTR(-EDESTADDRREQ);
 	}
 
-	key = rx->key;
-	if (key && !rx->key->payload.data[0])
-		key = NULL;
+	if (p->key_desc) {
+		if (!*p->key_desc) {
+			key = NULL;
+		} else {
+			key = rxrpc_request_key(rx, p->key_desc, p->key_desc_len);
+			if (IS_ERR(key)) {
+				release_sock(&rx->sk);
+				return ERR_CAST(key);
+			}
+			put_key = true;
+		}
+	} else  {
+		key = rx->key;
+		if (key && !rx->key->payload.data[0])
+			key = NULL;
+	}
 
 	memset(&cp, 0, sizeof(cp));
 	cp.local		= rx->local;
 	cp.key			= rx->key;
-	cp.security_level	= rx->min_sec_level;
+	cp.security_level	= p->sec_level;
 	cp.exclusive		= rx->exclusive | p->exclusive;
 	cp.upgrade		= p->upgrade;
 	cp.service_id		= srx->srx_service;
@@ -613,6 +640,8 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
 	/* The socket is now unlocked */
 
 	rxrpc_put_peer(cp.peer);
+	if (put_key)
+		key_put(key);
 	_leave(" = %p\n", call);
 	return call;
 }
@@ -640,6 +669,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 		.command		= RXRPC_CMD_SEND_DATA,
 		.exclusive		= false,
 		.upgrade		= false,
+		.sec_level		= rx->min_sec_level,
+		.key_desc		= NULL,
 	};
 
 	_enter("");





More information about the linux-afs mailing list