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

From: David Howells
Date: Thu Jun 23 2022 - 09:30:51 EST


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@xxxxxxxxxx>
---

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("");