Messages in this thread Patch in this message | | | Subject | [RFC PATCH 8/8] rxrpc: Set call security params in sendmsg() cmsg | From | David Howells <> | Date | Thu, 23 Jun 2022 14:29:46 +0100 |
| |
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@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("");
| |