From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42C61430CC1 for ; Thu, 23 Jul 2026 10:06:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784801165; cv=none; b=JIlFSBbjxyvf0H8V77Dj9wpiq9MhsRjWNtsnWj9XmYTplTB1tobPl2gzE0HLMT1Kj/uMzhPGu0lRxJRbJn+mrpncFbP/aXc9ARn6OqEAecAi3hx7MkVD2pB5D0xMS4ZSbf0ZejSqinN8Avh/WdJQBZjpEECmlmqgcp62vmBqRaY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784801165; c=relaxed/simple; bh=UU58n+VwYeDW1RPVQcgUSWBKkk1X7ljbPAivDXAMMks=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XsNxx0Rli74paOxkFD/+a+gDKKA2IL3OT1bzeK2LsSIacdDjfmci663jMf4GkpLnZvOke3FV+8cgwxfN+9aucDzmDeI93UtJIU92jY+12NRf8U6lAnw3bWuqDsxxVo1JUIZPWWukCN/C/6LpSC8bRmbvnKcrZdxp3qt+EQDsD6o= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=eO9V92X+; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="eO9V92X+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1784801162; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xDDRK6Ahwysest8LRbUEt737BjEIvnPFKIwIiy6xC7E=; b=eO9V92X+tQnv+P9uLjq4WpzQCADltHlJj/V14x1MeUYXAJ4u2cLC0KezFuBrJ0ruZ9EFUr kjlmAn7zJimuInW+8ND5KVcDziszYrCxB+3Fy2p7peNLv5pw94xTm5W9kQvGAKmmMs9aRI iRW4/Vf9DOdrY6dwND6jjCpNow1kvtA= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-189-J8Lqg76RN3aTuPmoENVRkg-1; Thu, 23 Jul 2026 06:03:54 -0400 X-MC-Unique: J8Lqg76RN3aTuPmoENVRkg-1 X-Mimecast-MFC-AGG-ID: J8Lqg76RN3aTuPmoENVRkg_1784801032 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3F0911955F31; Thu, 23 Jul 2026 10:03:52 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.33.159]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5E5353000225; Thu, 23 Jul 2026 10:03:48 +0000 (UTC) From: David Howells To: netdev@vger.kernel.org Cc: David Howells , Marc Dionne , Jakub Kicinski , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , linux-afs@lists.infradead.org, linux-kernel@vger.kernel.org, Jeffrey Altman , Jarkko Sakkinen , keyrings@vger.kernel.org, stable@kernel.org Subject: [PATCH net v4 7/9] rxrpc: Pass appdata key to rxrpc_call and thence to rxrpc_bundle Date: Thu, 23 Jul 2026 11:03:03 +0100 Message-ID: <20260723100309.530157-8-dhowells@redhat.com> In-Reply-To: <20260723100309.530157-1-dhowells@redhat.com> References: <20260723100309.530157-1-dhowells@redhat.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 Currently, when a CHALLENGE packet comes in, it's queued in an OOB queue on the AF_RXRPC socket that generated one of the calls on that connection for the application (which might be in userspace) to service. The application then picks up the CHALLENGE and requests a RESPONSE packet be generated, allowing the app to include app-specific data in it if appropriate. There is, however, no actual limit on the capacity of the CHALLENGE queue, and this could be abused remotely - and also getting the OOB mechanism right has proven tricky. Further, by analogy with other AFS codebases, it's not actually necessary to generate the application data in response to the CHALLENGE. The reason I did this was to set the encryption on the app-data to be the same as that specified in the CHALLENGE as the server must be able to handle that. However, it's sufficient to use the encoding type set in the token that is going to be sent to the server; presumably the kerberos server knows that the fileserver can handle that type - otherwise why tell the client to use it? This is a part of the fix. With this, the appdata key created by the AFS filesystem or passed in via sendmsg CMSG to a user AF_RXRPC socket is added to an rxrpc_call struct and will then be added to an rxrpc_bundle struct. Note that afs_make_op_call() has to be moved so that it can call afs_use_server(). afs_operation-based calls did not heretofore 'use' the server and server will be 'un-used' by afs_free_call(). Fixes: 5800b1cf3fd8 ("rxrpc: Allow CHALLENGEs to the passed to the app for a RESPONSE") Link: https://sashiko.dev/#/patchset/20260624163819.3017002-1-dhowells%40redhat.com Signed-off-by: David Howells cc: Marc Dionne cc: Jeffrey Altman cc: Eric Dumazet cc: "David S. Miller" cc: Jakub Kicinski cc: Paolo Abeni cc: Simon Horman cc: Jarkko Sakkinen cc: linux-afs@lists.infradead.org cc: keyrings@vger.kernel.org cc: stable@kernel.org --- fs/afs/internal.h | 31 ++++++++++++++++--------------- fs/afs/rxrpc.c | 21 ++++++++++++++++++++- include/net/af_rxrpc.h | 1 + include/trace/events/afs.h | 1 + include/uapi/linux/rxrpc.h | 1 + net/rxrpc/af_rxrpc.c | 3 +++ net/rxrpc/ar-internal.h | 3 +++ net/rxrpc/call_object.c | 2 ++ net/rxrpc/conn_client.c | 4 ++++ net/rxrpc/proc.c | 5 +++-- net/rxrpc/sendmsg.c | 26 +++++++++++++++++++++++++- 11 files changed, 79 insertions(+), 19 deletions(-) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index a8f303c20ef7..f75e007e483e 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1418,21 +1418,6 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why) __builtin_return_address(0)); } -static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call, - gfp_t gfp) -{ - struct afs_addr_list *alist = op->estate->addresses; - - op->call = call; - op->type = call->type; - call->op = op; - call->key = op->key; - call->intr = !(op->flags & AFS_OPERATION_UNINTR); - call->peer = rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer); - call->service_id = op->server->service_id; - afs_make_call(call, gfp); -} - static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size) { call->iov_len = size; @@ -1764,6 +1749,22 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) return &vnode->netfs.inode; } +static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call, + gfp_t gfp) +{ + struct afs_addr_list *alist = op->estate->addresses; + + op->call = call; + op->type = call->type; + call->op = op; + call->server = afs_use_server(op->server, false, afs_server_trace_use_call); + call->key = op->key; + call->intr = !(op->flags & AFS_OPERATION_UNINTR); + call->peer = rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer); + call->service_id = op->server->service_id; + afs_make_call(call, gfp); +} + /* * Note that a dentry got changed. We need to set d_fsdata to the data version * number derived from the result of the operation. It doesn't matter if diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index d82916657a3d..c25d0bc25517 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -347,6 +347,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp) struct rxrpc_call *rxcall; struct msghdr msg; struct kvec iov[1]; + struct key *app_data = NULL; size_t len; s64 tx_total_len; int ret; @@ -378,8 +379,26 @@ void afs_make_call(struct afs_call *call, gfp_t gfp) call->drop_ref = true; } + if (call->key && call->server) { + u32 krb5_enctype = 0; + u8 security_index = 0; + + rxrpc_kernel_query_key(call->key, &security_index, &krb5_enctype); + switch (security_index) { +#ifdef CONFIG_RXGK + case RXRPC_SECURITY_YFS_RXGK: + /* Read the key pointer before the appdata */ + app_data = smp_load_acquire(&call->server->yfs_rxgk_appdata); + break; +#endif + default: + break; + } + } + /* create a call */ - rxcall = rxrpc_kernel_begin_call(call->net->socket, call->peer, call->key, + rxcall = rxrpc_kernel_begin_call(call->net->socket, call->peer, + call->key, app_data, (unsigned long)call, tx_total_len, call->max_lifespan, diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index c4b68049c06f..19c61a2f5af3 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -55,6 +55,7 @@ void rxrpc_kernel_set_notifications(struct socket *sock, struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, struct rxrpc_peer *peer, struct key *key, + struct key *app_data, unsigned long user_call_ID, s64 tx_total_len, u32 hard_timeout, diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 1b3c48b5591d..04b0bb682b81 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -148,6 +148,7 @@ enum yfs_cm_operation { EM(afs_server_trace_unuse_slist_isort, "UNU isort") \ EM(afs_server_trace_update, "UPDATE ") \ EM(afs_server_trace_use_by_uuid, "USE uuid ") \ + EM(afs_server_trace_use_call, "USE call ") \ EM(afs_server_trace_use_cm_call, "USE cm-cl") \ EM(afs_server_trace_use_get_caps, "USE gcaps") \ EM(afs_server_trace_use_give_up_cb, "USE gvupc") \ diff --git a/include/uapi/linux/rxrpc.h b/include/uapi/linux/rxrpc.h index d9735abd4c79..bcdfdf9c67a1 100644 --- a/include/uapi/linux/rxrpc.h +++ b/include/uapi/linux/rxrpc.h @@ -63,6 +63,7 @@ enum rxrpc_cmsg_type { RXRPC_RESPOND = 17, /* Cs-: Respond to a challenge */ RXRPC_RESPONDED = 18, /* S-r: Data received in RESPONSE */ RXRPC_RESP_RXGK_APPDATA = 19, /* Cs-: RESPONSE: RxGK app data to include */ + RXRPC_RESPONSE_APPDATA = 20, /* Cs-: User key holding app data for RESPONSE */ RXRPC__SUPPORTED }; diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 9ab0f22c881e..a19c0fd3c51a 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -318,6 +318,7 @@ EXPORT_SYMBOL(rxrpc_kernel_put_peer); * @sock: The socket on which to make the call * @peer: The peer to contact * @key: The security context to use (defaults to socket setting) + * @app_data: The security response application data (or NULL) * @user_call_ID: The ID to use * @tx_total_len: Total length of data to transmit during the call (or -1) * @hard_timeout: The maximum lifespan of the call in sec @@ -340,6 +341,7 @@ EXPORT_SYMBOL(rxrpc_kernel_put_peer); struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, struct rxrpc_peer *peer, struct key *key, + struct key *app_data, unsigned long user_call_ID, s64 tx_total_len, u32 hard_timeout, @@ -368,6 +370,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, key = NULL; /* a no-security key */ memset(&p, 0, sizeof(p)); + p.app_data = app_data; p.user_call_ID = user_call_ID; p.tx_total_len = tx_total_len; p.interruptibility = interruptibility; diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index a6f830c1621f..6e16df7173d3 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -516,6 +516,7 @@ struct rxrpc_bundle { struct rxrpc_local *local; /* Representation of local endpoint */ struct rxrpc_peer *peer; /* Remote endpoint */ struct key *key; /* Security details */ + struct key *app_data; /* Security response app data */ struct list_head proc_link; /* Link in net->bundle_proc_list */ const struct rxrpc_security *security; /* applied security module */ refcount_t ref; @@ -720,6 +721,7 @@ struct rxrpc_call { struct rxrpc_sock __rcu *socket; /* socket responsible */ struct rxrpc_net *rxnet; /* Network namespace to which call belongs */ struct key *key; /* Security details */ + struct key *app_data; /* Security response app data */ const struct rxrpc_security *security; /* applied security module */ struct mutex user_mutex; /* User access mutex */ struct sockaddr_rxrpc dest_srx; /* Destination address */ @@ -914,6 +916,7 @@ enum rxrpc_command { }; struct rxrpc_call_params { + struct key *app_data; /* Security response app data */ s64 tx_total_len; /* Total Tx data length (if send data) */ unsigned long user_call_ID; /* User's call ID */ struct { diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 817ed9acb91e..9f6130d90c4c 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -211,6 +211,7 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, call->interruptibility = p->interruptibility; call->tx_total_len = p->tx_total_len; call->key = key_get(cp->key); + call->app_data = key_get(p->app_data); call->peer = rxrpc_get_peer(cp->peer, rxrpc_peer_get_call); call->local = rxrpc_get_local(cp->local, rxrpc_local_get_call); call->security_level = cp->security_level; @@ -697,6 +698,7 @@ static void rxrpc_destroy_call(struct work_struct *work) rxrpc_put_peer(call->peer, rxrpc_peer_put_call); rxrpc_put_local(call->local, rxrpc_local_put_call); key_put(call->key); + key_put(call->app_data); call_rcu(&call->rcu, rxrpc_rcu_free_call); } diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 48519f0de185..dd79630d3066 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -81,6 +81,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_call *call, bundle->local = call->local; bundle->peer = rxrpc_get_peer(call->peer, rxrpc_peer_get_bundle); bundle->key = key_get(call->key); + bundle->app_data = key_get(call->app_data); bundle->security = call->security; bundle->exclusive = test_bit(RXRPC_CALL_EXCLUSIVE, &call->flags); bundle->upgrade = test_bit(RXRPC_CALL_UPGRADE, &call->flags); @@ -118,6 +119,7 @@ static void rxrpc_free_bundle(struct rxrpc_bundle *bundle) write_unlock(&bundle->local->rxnet->conn_lock); rxrpc_put_peer(bundle->peer, rxrpc_peer_put_bundle); key_put(bundle->key); + key_put(bundle->app_data); kfree(bundle); } @@ -274,6 +276,7 @@ int rxrpc_look_up_bundle(struct rxrpc_call *call, gfp_t gfp) #define cmp(X, Y) ((long)(X) - (long)(Y)) diff = (cmp(bundle->peer, call->peer) ?: cmp(bundle->key, call->key) ?: + cmp(bundle->app_data, call->app_data) ?: cmp(bundle->security_level, call->security_level) ?: cmp(bundle->upgrade, upgrade)); #undef cmp @@ -303,6 +306,7 @@ int rxrpc_look_up_bundle(struct rxrpc_call *call, gfp_t gfp) #define cmp(X, Y) ((long)(X) - (long)(Y)) diff = (cmp(bundle->peer, call->peer) ?: cmp(bundle->key, call->key) ?: + cmp(bundle->app_data, call->app_data) ?: cmp(bundle->security_level, call->security_level) ?: cmp(bundle->upgrade, upgrade)); #undef cmp diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c index e9a27fa7b25d..f300491b06bd 100644 --- a/net/rxrpc/proc.c +++ b/net/rxrpc/proc.c @@ -238,7 +238,7 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "Proto Local " " Remote " - " SvID Ref Act Flg Key |" + " SvID Ref Act Flg Key AppData |" " Bundle Conn_0 Conn_1 Conn_2 Conn_3\n" ); return 0; @@ -250,7 +250,7 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v) scnprintf(rbuff, sizeof(rbuff), "%pISpc", &bundle->peer->srx.transport); seq_printf(seq, "UDP %-47.47s %-47.47s %4x %3u %3d" - " %c%c%c %08x | %08x %08x %08x %08x %08x\n", + " %c%c%c %08x %08x | %08x %08x %08x %08x %08x\n", lbuff, rbuff, bundle->service_id, @@ -260,6 +260,7 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v) bundle->exclusive ? 'e' : '-', bundle->upgrade ? 'u' : '-', key_serial(bundle->key), + key_serial(bundle->app_data), bundle->debug_id, bundle->conn_ids[0], bundle->conn_ids[1], diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index df7dc1c942a3..b3f765fd41bc 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -544,6 +545,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p) { struct cmsghdr *cmsg; + key_serial_t key_id; + key_ref_t key; bool got_user_ID = false; int len; @@ -628,6 +631,23 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p) return -ERANGE; break; + case RXRPC_RESPONSE_APPDATA: + if (len != sizeof(key_serial_t)) + return -EINVAL; + if (p->call.app_data) + return -EINVAL; + key_id = *(key_serial_t *)CMSG_DATA(cmsg); + key = lookup_user_key(key_id, 0, KEY_NEED_SEARCH); + if (IS_ERR(key)) + return PTR_ERR(key); + if (key_ref_to_ptr(key)->type != &key_type_user && + key_ref_to_ptr(key)->type != &key_type_logon) { + key_ref_put(key); + return -EINVAL; + } + p->call.app_data = key_ref_to_ptr(key); + break; + default: return -EINVAL; } @@ -736,8 +756,10 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) goto error_release_sock; call = rxrpc_new_client_call_for_sendmsg(rx, msg, &p); /* The socket is now unlocked... */ - if (IS_ERR(call)) + if (IS_ERR(call)) { + key_put(p.call.app_data); return PTR_ERR(call); + } /* ... and we have the call lock. */ p.call.nr_timeouts = 0; ret = 0; @@ -822,11 +844,13 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) mutex_unlock(&call->user_mutex); error_put: rxrpc_put_call(call, rxrpc_call_put_sendmsg); + key_put(p.call.app_data); _leave(" = %d", ret); return ret; error_release_sock: release_sock(&rx->sk); + key_put(p.call.app_data); return ret; }