| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/07 14:49 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"AF_RXRPC",
"AFS_FS",
"RXGK",
"RXPERF"
],
"FocusSymbols": [
"rxrpc_send_data",
"rxrpc_do_sendmsg",
"rxrpc_kernel_send_data",
"rxrpc_recvmsg",
"rxrpc_notify_socket",
"rxrpc_poke_conn",
"rxrpc_preparse_xdr_yfs_rxgk",
"rxgk_init_connection_security",
"afs_make_call",
"afs_send_simple_reply",
"afs_send_empty_reply",
"afs_create_yfs_cm_token",
"rxperf_process_call"
],
"KMSANReasoning": "The patch series modifies the AF_RXRPC and AFS networking code to support short writes in rxrpc_kernel_send_data, loop until full message consumption in AFS/rxperf callers, simplify locking around rxrpc_send_data, fix the toksize calculation for YFS CM tokens, add encryption type validation for YFS keys, and clean up socket notification and connection refcounting.\n\nNone of these changes expose uninitialized memory risks or kernel-to-user info leaks:\n- The token buffer in `afs_create_yfs_cm_token` is allocated with `kzalloc`, zeroing all bytes; the fix merely accounts for the 4-byte `level` field in `toksize`.\n- In `rxrpc_send_data`, data transfer continues to use `copy_from_iter_full` with bounded copy sizes (`min3`), and error-rewind logic updates byte counters appropriately.\n- Local variables across modified functions (`ret`, `n`, `rewind_by`, etc.) are explicitly initialized or assigned before use.\n- No kernel structures copied to user space (via `copy_to_user`, ioctl, netlink, etc.) or uninitialized padding/struct fields are introduced or altered.\n\nAny concurrency, refcounting, or bounds issues that might arise are fully detectable by standard debug builds (KASAN, LOCKDEP). Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies RxRPC socket data sending and completion notification mechanisms, connection reference counting, key payload parsing, and in-kernel AFS/rxperf send paths. These changes involve core networking and filesystem state machines and error-handling paths that are fully reachable via AF_RXRPC sockets, keys syscalls, and AFS operations in standard virtualized environments.",
"WorthFuzzing": true
} |
| 1/1 | 2026/09/07 14:49 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 3d3aff233769081693eda889b58aa3203a62892e\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Sep 7 14:49:22 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst\nindex 8926dab8e2e60..7df6aff7644c0 100644\n--- a/Documentation/networking/rxrpc.rst\n+++ b/Documentation/networking/rxrpc.rst\n@@ -879,14 +879,21 @@ The kernel interface functions are as follows:\n exclusively to in-kernel virtual addresses. msg.msg_flags may be given\n MSG_MORE if there will be subsequent data sends for this call.\n \n- The msg must not specify a destination address, control data or any flags\n- other than MSG_MORE. len is the total amount of data to transmit.\n+ msg must not specify a destination address, control data or any flags\n+ other than MSG_MORE. len is the amount of data to add to the\n+ transmission. The last-packet flag will only be set on the outgoing\n+ packet if MSG_MORE is not set and len amount of bytes are buffered.\n \n notify_end_rx can be NULL or it can be used to specify a function to be\n called when the call changes state to end the Tx phase. This function is\n called with a spinlock held to prevent the last DATA packet from being\n transmitted until the function returns.\n \n+ The function returns the amount of data buffered or an error. It will\n+ return zero only if len is 0 or if msg-\u003emsg_iter is empty. It may also\n+ make a short write, buffering less than the amount of data provided or the\n+ len specified, in which case it should be called again.\n+\n (#) Receive data from a call::\n \n \tint rxrpc_kernel_recv_data(struct socket *sock,\ndiff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c\nindex 103168c70dd4d..5eeeef761cf31 100644\n--- a/fs/afs/cm_security.c\n+++ b/fs/afs/cm_security.c\n@@ -235,7 +235,7 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n \t *\tstruct RXGK_AuthName\tidentities\u003c\u003e;\n \t * };\n \t */\n-\ttoksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);\n+\ttoksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);\n \n \toffset = 0;\n \tencsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, \u0026offset);\ndiff --git a/fs/afs/internal.h b/fs/afs/internal.h\nindex 290873bac89b3..65a0866cd8b85 100644\n--- a/fs/afs/internal.h\n+++ b/fs/afs/internal.h\n@@ -1416,22 +1416,6 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)\n \t\t __builtin_return_address(0));\n }\n \n-static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,\n-\t\t\t\t gfp_t gfp)\n-{\n-\tstruct afs_addr_list *alist = op-\u003eestate-\u003eaddresses;\n-\n-\top-\u003ecall\t= afs_get_call(call, afs_call_trace_get);\n-\top-\u003etype\t= call-\u003etype;\n-\tcall-\u003eop\t= op;\n-\tcall-\u003ekey\t= op-\u003ekey;\n-\tcall-\u003eintr\t= !(op-\u003eflags \u0026 AFS_OPERATION_UNINTR);\n-\tcall-\u003epeer\t= rxrpc_kernel_get_peer(alist-\u003eaddrs[op-\u003eaddr_index].peer);\n-\tcall-\u003eservice_id = op-\u003eserver-\u003eservice_id;\n-\tafs_make_call(call, gfp);\n-\tafs_put_call(call);\n-}\n-\n static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)\n {\n \tcall-\u003eiov_len = size;\n@@ -1763,6 +1747,23 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)\n \treturn \u0026vnode-\u003enetfs.inode;\n }\n \n+static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,\n+\t\t\t\t gfp_t gfp)\n+{\n+\tstruct afs_addr_list *alist = op-\u003eestate-\u003eaddresses;\n+\n+\top-\u003ecall\t= afs_get_call(call, afs_call_trace_get);\n+\top-\u003etype\t= call-\u003etype;\n+\tcall-\u003eop\t= op;\n+\tcall-\u003eserver\t= afs_use_server(op-\u003eserver, false, afs_server_trace_use_call);\n+\tcall-\u003ekey\t= op-\u003ekey;\n+\tcall-\u003eintr\t= !(op-\u003eflags \u0026 AFS_OPERATION_UNINTR);\n+\tcall-\u003epeer\t= rxrpc_kernel_get_peer(alist-\u003eaddrs[op-\u003eaddr_index].peer);\n+\tcall-\u003eservice_id = op-\u003eserver-\u003eservice_id;\n+\tafs_make_call(call, gfp);\n+\tafs_put_call(call);\n+}\n+\n /*\n * Note that a dentry got changed. We need to set d_fsdata to the data version\n * number derived from the result of the operation. It doesn't matter if\ndiff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c\nindex d82916657a3dd..1f5b6aa689433 100644\n--- a/fs/afs/rxrpc.c\n+++ b/fs/afs/rxrpc.c\n@@ -412,26 +412,32 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \tmsg.msg_controllen\t= 0;\n \tmsg.msg_flags\t\t= MSG_WAITALL | (call-\u003ewrite_iter ? MSG_MORE : 0);\n \n-\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket, rxcall,\n-\t\t\t\t \u0026msg, call-\u003erequest_size,\n-\t\t\t\t afs_notify_end_request_tx);\n-\tif (ret \u003c 0)\n-\t\tgoto error_do_abort;\n+\tdo {\n+\t\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket, rxcall, \u0026msg,\n+\t\t\t\t\t msg_data_left(\u0026msg),\n+\t\t\t\t\t afs_notify_end_request_tx);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto error_do_abort;\n+\t} while (msg_data_left(\u0026msg) \u003e 0);\n \n \tif (call-\u003ewrite_iter) {\n \t\tmsg.msg_iter = *call-\u003ewrite_iter;\n \t\tmsg.msg_flags \u0026= ~MSG_MORE;\n \t\ttrace_afs_send_data(call, \u0026msg);\n \n-\t\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket,\n-\t\t\t\t\t call-\u003erxcall, \u0026msg,\n-\t\t\t\t\t iov_iter_count(\u0026msg.msg_iter),\n-\t\t\t\t\t afs_notify_end_request_tx);\n+\t\tdo {\n+\t\t\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket,\n+\t\t\t\t\t\t call-\u003erxcall, \u0026msg,\n+\t\t\t\t\t\t msg_data_left(\u0026msg),\n+\t\t\t\t\t\t afs_notify_end_request_tx);\n+\t\t\tif (ret \u003c 0) {\n+\t\t\t\ttrace_afs_sent_data(call, \u0026msg, ret);\n+\t\t\t\tgoto error_do_abort;\n+\t\t\t}\n+\t\t} while (msg_data_left(\u0026msg) \u003e 0);\n \t\t*call-\u003ewrite_iter = msg.msg_iter;\n \n-\t\ttrace_afs_sent_data(call, \u0026msg, ret);\n-\t\tif (ret \u003c 0)\n-\t\t\tgoto error_do_abort;\n+\t\ttrace_afs_sent_data(call, \u0026msg, 0);\n \t}\n \n \t/* Note that at this point, we may have received the reply or an abort\n@@ -443,10 +449,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \treturn;\n \n error_do_abort:\n-\tif (ret != -ECONNABORTED)\n-\t\trxrpc_kernel_abort_call(call-\u003enet-\u003esocket, rxcall,\n-\t\t\t\t\tRX_USER_ABORT, ret,\n-\t\t\t\t\tafs_abort_send_data_error);\n+\trxrpc_kernel_abort_call(call-\u003enet-\u003esocket, rxcall,\n+\t\t\t\tRX_USER_ABORT, ret, afs_abort_send_data_error);\n \tif (call-\u003easync) {\n \t\tafs_see_call(call, afs_call_trace_async_abort);\n \t\treturn;\n@@ -859,6 +863,7 @@ void afs_send_empty_reply(struct afs_call *call)\n {\n \tstruct afs_net *net = call-\u003enet;\n \tstruct msghdr msg;\n+\tint ret;\n \n \t_enter(\"\");\n \n@@ -871,22 +876,13 @@ void afs_send_empty_reply(struct afs_call *call)\n \tmsg.msg_controllen\t= 0;\n \tmsg.msg_flags\t\t= 0;\n \n-\tswitch (rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg, 0,\n-\t\t\t\t afs_notify_end_reply_tx)) {\n-\tcase 0:\n-\t\t_leave(\" [replied]\");\n+\tret = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg, 0,\n+\t\t\t\t afs_notify_end_reply_tx);\n+\tif (ret \u003e= 0) /* Shouldn't buffer more than 0 bytes. */\n \t\treturn;\n \n-\tcase -ENOMEM:\n-\t\t_debug(\"oom\");\n-\t\trxrpc_kernel_abort_call(net-\u003esocket, call-\u003erxcall,\n-\t\t\t\t\tRXGEN_SS_MARSHAL, -ENOMEM,\n-\t\t\t\t\tafs_abort_oom);\n-\t\tfallthrough;\n-\tdefault:\n-\t\t_leave(\" [error]\");\n-\t\treturn;\n-\t}\n+\trxrpc_kernel_abort_call(net-\u003esocket, call-\u003erxcall,\n+\t\t\t\tRXGEN_SS_MARSHAL, ret, afs_abort_send_error);\n }\n \n /*\n@@ -912,20 +908,21 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)\n \tmsg.msg_controllen\t= 0;\n \tmsg.msg_flags\t\t= 0;\n \n-\tn = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg, len,\n-\t\t\t\t afs_notify_end_reply_tx);\n+\tdo {\n+\t\tn = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall,\n+\t\t\t\t\t \u0026msg, msg_data_left(\u0026msg),\n+\t\t\t\t\t afs_notify_end_reply_tx);\n+\t} while (n \u003e= 0 \u0026\u0026 msg_data_left(\u0026msg) \u003e 0);\n+\n \tif (n \u003e= 0) {\n \t\t/* Success */\n \t\t_leave(\" [replied]\");\n \t\treturn;\n \t}\n \n-\tif (n == -ENOMEM) {\n-\t\t_debug(\"oom\");\n-\t\trxrpc_kernel_abort_call(net-\u003esocket, call-\u003erxcall,\n-\t\t\t\t\tRXGEN_SS_MARSHAL, -ENOMEM,\n-\t\t\t\t\tafs_abort_oom);\n-\t}\n+\n+\trxrpc_kernel_abort_call(net-\u003esocket, call-\u003erxcall,\n+\t\t\t\tRXGEN_SS_MARSHAL, n, afs_abort_send_error);\n \t_leave(\" [error]\");\n }\n \ndiff --git a/include/trace/events/afs.h b/include/trace/events/afs.h\nindex 1b3c48b5591df..04b0bb682b810 100644\n--- a/include/trace/events/afs.h\n+++ b/include/trace/events/afs.h\n@@ -148,6 +148,7 @@ enum yfs_cm_operation {\n \tEM(afs_server_trace_unuse_slist_isort,\t\"UNU isort\") \\\n \tEM(afs_server_trace_update,\t\t\"UPDATE \") \\\n \tEM(afs_server_trace_use_by_uuid,\t\"USE uuid \") \\\n+\tEM(afs_server_trace_use_call,\t\t\"USE call \") \\\n \tEM(afs_server_trace_use_cm_call,\t\"USE cm-cl\") \\\n \tEM(afs_server_trace_use_get_caps,\t\"USE gcaps\") \\\n \tEM(afs_server_trace_use_give_up_cb,\t\"USE gvupc\") \\\ndiff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h\nindex 704a10de66700..52f8718cf7250 100644\n--- a/include/trace/events/rxrpc.h\n+++ b/include/trace/events/rxrpc.h\n@@ -20,16 +20,16 @@\n \t/* AFS errors */\t\t\t\t\t\t\\\n \tEM(afs_abort_general_error,\t\t\"afs-error\")\t\t\\\n \tEM(afs_abort_interrupted,\t\t\"afs-intr\")\t\t\\\n-\tEM(afs_abort_oom,\t\t\t\"afs-oom\")\t\t\\\n \tEM(afs_abort_op_not_supported,\t\t\"afs-op-notsupp\")\t\\\n \tEM(afs_abort_probeuuid_negative,\t\"afs-probeuuid-neg\")\t\\\n \tEM(afs_abort_send_data_error,\t\t\"afs-send-data\")\t\\\n+\tEM(afs_abort_send_error,\t\t\"afs-send-error\")\t\\\n \tEM(afs_abort_unmarshal_error,\t\t\"afs-unmarshal\")\t\\\n \tEM(afs_abort_unsupported_sec_class,\t\"afs-unsup-sec-class\")\t\\\n \t/* rxperf errors */\t\t\t\t\t\t\\\n \tEM(rxperf_abort_general_error,\t\t\"rxperf-error\")\t\t\\\n-\tEM(rxperf_abort_oom,\t\t\t\"rxperf-oom\")\t\t\\\n \tEM(rxperf_abort_op_not_supported,\t\"rxperf-op-notsupp\")\t\\\n+\tEM(rxperf_abort_send_error,\t\t\"rxperf-send-error\")\t\\\n \tEM(rxperf_abort_unmarshal_error,\t\"rxperf-unmarshal\")\t\\\n \t/* RxKAD security errors */\t\t\t\t\t\\\n \tEM(rxkad_abort_1_short_check,\t\t\"rxkad1-short-check\")\t\\\n@@ -148,6 +148,7 @@\n \tEM(rxrpc_eproto_wrong_security,\t\t\"wrong-sec\")\t\t\\\n \tEM(rxrpc_recvmsg_excess_data,\t\t\"recvmsg-excess\")\t\\\n \tEM(rxrpc_recvmsg_short_data,\t\t\"recvmsg-short\")\t\\\n+\tEM(rxrpc_sendmsg_tx_error,\t\t\"tx-error\")\t\t\\\n \tE_(rxrpc_sendmsg_late_send,\t\t\"sendmsg-late\")\n \n #define rxrpc_call_poke_traces \\\n@@ -342,6 +343,7 @@\n \tEM(rxrpc_call_see_distribute_error,\t\"SEE dist-err\") \\\n \tEM(rxrpc_call_see_input,\t\t\"SEE input \") \\\n \tEM(rxrpc_call_see_notify_released,\t\"SEE nfy-rlsd\") \\\n+\tEM(rxrpc_call_see_notify_skipped,\t\"SEE nfy-skip\") \\\n \tEM(rxrpc_call_see_recvmsg,\t\t\"SEE recvmsg \") \\\n \tEM(rxrpc_call_see_recvmsg_requeue,\t\"SEE recv-rqu\") \\\n \tEM(rxrpc_call_see_recvmsg_requeue_first, \"SEE recv-rqF\") \\\ndiff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h\nindex 865f05fe37ab9..cb36a709f540e 100644\n--- a/net/rxrpc/ar-internal.h\n+++ b/net/rxrpc/ar-internal.h\n@@ -642,6 +642,7 @@ enum rxrpc_call_flag {\n \tRXRPC_CALL_TX_LAST,\t\t/* Last packet in Tx buffer (at rxtx_top) */\n \tRXRPC_CALL_TX_ALL_ACKED,\t/* Last packet has been hard-acked */\n \tRXRPC_CALL_TX_NO_MORE,\t\t/* No more data to transmit (MSG_MORE deasserted) */\n+\tRXRPC_CALL_TX_ERROR,\t\t/* Terminal error; call needs abort */\n \tRXRPC_CALL_SEND_PING,\t\t/* A ping will need to be sent */\n \tRXRPC_CALL_RETRANS_TIMEOUT,\t/* Retransmission due to timeout occurred */\n \tRXRPC_CALL_BEGAN_RX_TIMER,\t/* We began the expect_rx_by timer */\n@@ -1109,6 +1110,7 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)\n /*\n * call_state.c\n */\n+void rxrpc_notify_socket(struct rxrpc_call *call);\n bool rxrpc_set_call_completion(struct rxrpc_call *call,\n \t\t\t enum rxrpc_call_completion compl,\n \t\t\t u32 abort_code,\n@@ -1441,7 +1443,6 @@ extern const struct seq_operations rxrpc_local_seq_ops;\n /*\n * recvmsg.c\n */\n-void rxrpc_notify_socket(struct rxrpc_call *);\n int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);\n \n /*\ndiff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c\nindex 6afb54373ebbf..364810c652766 100644\n--- a/net/rxrpc/call_state.c\n+++ b/net/rxrpc/call_state.c\n@@ -7,6 +7,60 @@\n \n #include \"ar-internal.h\"\n \n+/*\n+ * Post a call for attention by the socket or kernel service.\n+ */\n+static void __rxrpc_notify_socket(struct rxrpc_call *call)\n+{\n+\tstruct rxrpc_sock *rx;\n+\tstruct sock *sk;\n+\tunsigned long flags;\n+\n+\tif (test_bit(RXRPC_CALL_RELEASED, \u0026call-\u003eflags)) {\n+\t\trxrpc_see_call(call, rxrpc_call_see_notify_released);\n+\t\treturn;\n+\t}\n+\n+\trcu_read_lock();\n+\n+\trx = rcu_dereference(call-\u003esocket);\n+\tsk = \u0026rx-\u003esk;\n+\tif (rx \u0026\u0026 sk-\u003esk_state \u003c RXRPC_CLOSE) {\n+\t\tif (call-\u003enotify_rx) {\n+\t\t\tspin_lock_irqsave(\u0026call-\u003enotify_lock, flags);\n+\t\t\tcall-\u003enotify_rx(sk, call, call-\u003euser_call_ID);\n+\t\t\tspin_unlock_irqrestore(\u0026call-\u003enotify_lock, flags);\n+\t\t} else {\n+\t\t\tspin_lock_irqsave(\u0026rx-\u003erecvmsg_lock, flags);\n+\t\t\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n+\t\t\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n+\t\t\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n+\t\t\t}\n+\t\t\tspin_unlock_irqrestore(\u0026rx-\u003erecvmsg_lock, flags);\n+\n+\t\t\tif (!sock_flag(sk, SOCK_DEAD)) {\n+\t\t\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n+\t\t\t\tsk-\u003esk_data_ready(sk);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\trcu_read_unlock();\n+}\n+\n+/*\n+ * Post a call for attention by the socket or kernel service.\n+ */\n+void rxrpc_notify_socket(struct rxrpc_call *call)\n+{\n+\tif (rxrpc_call_is_complete(call)) {\n+\t\trxrpc_see_call(call, rxrpc_call_see_notify_skipped);\n+\t\treturn;\n+\t}\n+\n+\t__rxrpc_notify_socket(call);\n+}\n+\n /*\n * Transition a call to the complete state.\n */\n@@ -25,7 +79,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,\n \trxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);\n \ttrace_rxrpc_call_complete(call);\n \twake_up(\u0026call-\u003ewaitq);\n-\trxrpc_notify_socket(call);\n+\t__rxrpc_notify_socket(call);\n \treturn true;\n }\n \ndiff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c\nindex 0ece717db0f85..1be50e0c9cee5 100644\n--- a/net/rxrpc/conn_object.c\n+++ b/net/rxrpc/conn_object.c\n@@ -34,7 +34,10 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)\n \tspin_lock_irq(\u0026local-\u003elock);\n \tbusy = !list_empty(\u0026conn-\u003eattend_link);\n \tif (!busy) {\n-\t\trxrpc_get_connection(conn, why);\n+\t\tif (!rxrpc_get_connection_maybe(conn, why)) {\n+\t\t\tspin_unlock_irq(\u0026local-\u003elock);\n+\t\t\treturn;\n+\t\t}\n \t\tlist_add_tail(\u0026conn-\u003eattend_link, \u0026local-\u003econn_attend_q);\n \t}\n \tspin_unlock_irq(\u0026local-\u003elock);\ndiff --git a/net/rxrpc/key.c b/net/rxrpc/key.c\nindex a0aa78d892897..30d6db052c216 100644\n--- a/net/rxrpc/key.c\n+++ b/net/rxrpc/key.c\n@@ -172,6 +172,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\n \tconst __be32 *ticket, *key;\n \ts64 tmp;\n \tsize_t raw_keylen, raw_tktlen, keylen, tktlen;\n+\tint ret = -EKEYREJECTED;\n \n \t_enter(\",{%x,%x,%x,%x},%x\",\n \t ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),\n@@ -229,6 +230,11 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\n \ttoken-\u003erxgk-\u003ekey.data\t= token-\u003erxgk-\u003e_key;\n \ttoken-\u003erxgk-\u003eticket.len = raw_tktlen;\n \n+\tif (!crypto_krb5_find_enctype(token-\u003erxgk-\u003eenctype)) {\n+\t\tret = -ENOPKG;\n+\t\tgoto reject_token;\n+\t}\n+\n \tif (token-\u003erxgk-\u003eendtime != 0) {\n \t\texpiry = rxrpc_s64_to_time64(token-\u003erxgk-\u003eendtime);\n \t\tif (expiry \u003c 0)\n@@ -280,7 +286,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\n \tkfree(token-\u003erxgk);\n \tkfree(token);\n reject:\n-\treturn -EKEYREJECTED;\n+\treturn ret;\n expired:\n \tkfree(token-\u003erxgk);\n \tkfree(token);\ndiff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c\nindex efcba4b2e74f0..28b2148b56936 100644\n--- a/net/rxrpc/recvmsg.c\n+++ b/net/rxrpc/recvmsg.c\n@@ -17,13 +17,12 @@\n #include \"ar-internal.h\"\n \n /*\n- * Post a call for attention by the socket or kernel service. Further\n- * notifications are suppressed by putting recvmsg_link on a dummy queue.\n+ * Requeue a call for recvmsg() to pick up.\n */\n-void rxrpc_notify_socket(struct rxrpc_call *call)\n+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)\n {\n-\tstruct rxrpc_sock *rx;\n-\tstruct sock *sk;\n+\tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n+\tstruct sock *sk = \u0026rx-\u003esk;\n \n \t_enter(\"%d\", call-\u003edebug_id);\n \n@@ -32,31 +31,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)\n \t\treturn;\n \t}\n \n-\trcu_read_lock();\n-\n-\trx = rcu_dereference(call-\u003esocket);\n-\tsk = \u0026rx-\u003esk;\n-\tif (rx \u0026\u0026 sk-\u003esk_state \u003c RXRPC_CLOSE) {\n-\t\tif (call-\u003enotify_rx) {\n-\t\t\tspin_lock_irq(\u0026call-\u003enotify_lock);\n-\t\t\tcall-\u003enotify_rx(sk, call, call-\u003euser_call_ID);\n-\t\t\tspin_unlock_irq(\u0026call-\u003enotify_lock);\n-\t\t} else {\n-\t\t\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n-\t\t\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n-\t\t\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n-\t\t\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n-\t\t\t}\n-\t\t\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n+\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n+\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n+\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n+\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n+\t}\n+\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n \n-\t\t\tif (!sock_flag(sk, SOCK_DEAD)) {\n-\t\t\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n-\t\t\t\tsk-\u003esk_data_ready(sk);\n-\t\t\t}\n-\t\t}\n+\tif (!sock_flag(sk, SOCK_DEAD)) {\n+\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n+\t\tsk-\u003esk_data_ready(sk);\n \t}\n \n-\trcu_read_unlock();\n \t_leave(\"\");\n }\n \n@@ -561,7 +547,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \n \tif (!(flags \u0026 MSG_PEEK) \u0026\u0026\n \t !skb_queue_empty(\u0026call-\u003erecvmsg_queue))\n-\t\trxrpc_notify_socket(call);\n+\t\trxrpc_requeue_call(sock, call);\n \tgoto not_yet_complete;\n \n call_failed:\ndiff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c\nindex 77a67ace1d248..b49221f57f677 100644\n--- a/net/rxrpc/rxgk.c\n+++ b/net/rxrpc/rxgk.c\n@@ -251,8 +251,10 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,\n \t\t\t\t\t GFP_NOFS);\n \tif (IS_ERR(gk))\n \t\treturn PTR_ERR(gk);\n+\twrite_lock(\u0026conn-\u003esecurity_use_lock);\n \tconn-\u003erxgk.enctype = gk-\u003ekrb5-\u003eetype;\n \tconn-\u003erxgk.keys[gk-\u003ekey_number \u0026 3] = gk;\n+\twrite_unlock(\u0026conn-\u003esecurity_use_lock);\n \n \tswitch (conn-\u003esecurity_level) {\n \tcase RXRPC_SECURITY_PLAIN:\ndiff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c\nindex b8df6d22314d6..ebd54222c64ef 100644\n--- a/net/rxrpc/rxperf.c\n+++ b/net/rxrpc/rxperf.c\n@@ -538,15 +538,18 @@ static int rxperf_process_call(struct rxperf_call *call)\n \tiov[0].iov_len\t= len;\n \tiov_iter_kvec(\u0026msg.msg_iter, WRITE, iov, 1, len);\n \tmsg.msg_flags = 0;\n-\tn = rxrpc_kernel_send_data(rxperf_socket, call-\u003erxcall, \u0026msg, len,\n-\t\t\t\t rxperf_notify_end_reply_tx);\n+\tdo {\n+\t\tn = rxrpc_kernel_send_data(rxperf_socket, call-\u003erxcall,\n+\t\t\t\t\t \u0026msg, msg_data_left(\u0026msg),\n+\t\t\t\t\t rxperf_notify_end_reply_tx);\n+\t} while (n \u003e= 0 \u0026\u0026 msg_data_left(\u0026msg) \u003e 0);\n+\n \tif (n \u003e= 0)\n \t\treturn 0; /* Success */\n \n-\tif (n == -ENOMEM)\n-\t\trxrpc_kernel_abort_call(rxperf_socket, call-\u003erxcall,\n-\t\t\t\t\tRXGEN_SS_MARSHAL, -ENOMEM,\n-\t\t\t\t\trxperf_abort_oom);\n+\trxrpc_kernel_abort_call(rxperf_socket, call-\u003erxcall,\n+\t\t\t\tRXGEN_SS_MARSHAL, n,\n+\t\t\t\trxperf_abort_send_error);\n \treturn n;\n }\n \ndiff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c\nindex ed2c9a51005ad..8bb327dc2833e 100644\n--- a/net/rxrpc/sendmsg.c\n+++ b/net/rxrpc/sendmsg.c\n@@ -320,8 +320,8 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)\n static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\t struct rxrpc_call *call,\n \t\t\t struct msghdr *msg, size_t len,\n-\t\t\t rxrpc_notify_end_tx_t notify_end_tx,\n-\t\t\t bool *_dropped_lock)\n+\t\t\t rxrpc_notify_end_tx_t notify_end_tx)\n+\t__releases(\u0026call-\u003euser_mutex)\n {\n \tstruct rxrpc_txbuf *txb;\n \tstruct sock *sk = \u0026rx-\u003esk;\n@@ -330,29 +330,37 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \tbool more = msg-\u003emsg_flags \u0026 MSG_MORE;\n \tint ret, copied = 0;\n \n-\tif (test_bit(RXRPC_CALL_TX_NO_MORE, \u0026call-\u003eflags)) {\n-\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_late_send,\n-\t\t\t\t call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n-\t\t\t\t 0, -EPROTO);\n-\t\treturn -EPROTO;\n-\t}\n-\n \ttimeo = sock_sndtimeo(sk, msg-\u003emsg_flags \u0026 MSG_DONTWAIT);\n \n \tret = rxrpc_wait_to_be_connected(call, \u0026timeo);\n \tif (ret \u003c 0)\n-\t\treturn ret;\n+\t\tgoto out_unlock;\n \n \tif (call-\u003econn-\u003estate == RXRPC_CONN_CLIENT_UNSECURED) {\n \t\tret = rxrpc_init_client_conn_security(call-\u003econn);\n \t\tif (ret \u003c 0)\n-\t\t\treturn ret;\n+\t\t\tgoto out_unlock;\n \t}\n \n \t/* this should be in poll */\n \tsk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);\n \n reload:\n+\tif (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, \u0026call-\u003eflags))) {\n+\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_late_send,\n+\t\t\t\t call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n+\t\t\t\t 0, -EPROTO);\n+\t\tret = -EPROTO;\n+\t\tgoto maybe_error;\n+\t}\n+\tif (unlikely(test_bit(RXRPC_CALL_TX_ERROR, \u0026call-\u003eflags))) {\n+\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_tx_error,\n+\t\t\t\t call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n+\t\t\t\t 0, -EIO);\n+\t\tret = -EIO;\n+\t\tgoto maybe_error;\n+\t}\n+\n \ttxb = call-\u003etx_pending;\n \tcall-\u003etx_pending = NULL;\n \tif (txb)\n@@ -379,9 +387,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \n \tret = -EMSGSIZE;\n \tif (call-\u003etx_total_len != -1) {\n-\t\tif (len - copied \u003e call-\u003etx_total_len)\n+\t\tif (len \u003e call-\u003etx_total_len)\n \t\t\tgoto maybe_error;\n-\t\tif (!more \u0026\u0026 len - copied != call-\u003etx_total_len)\n+\t\tif (!more \u0026\u0026 len != call-\u003etx_total_len)\n \t\t\tgoto maybe_error;\n \t}\n \n@@ -405,7 +413,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\t * the security header is going to be in the padded\n \t\t\t * region (enc blocksize), but the trailer is not.\n \t\t\t */\n-\t\t\tremain = more ? INT_MAX : msg_data_left(msg);\n+\t\t\tremain = more ? INT_MAX : len;\n \t\t\ttxb = call-\u003econn-\u003esecurity-\u003ealloc_txbuf(call, remain, sk-\u003esk_allocation);\n \t\t\tif (!txb) {\n \t\t\t\tret = -ENOMEM;\n@@ -416,8 +424,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t_debug(\"append\");\n \n \t\t/* append next segment of data to the current buffer */\n-\t\tif (msg_data_left(msg) \u003e 0) {\n-\t\t\tsize_t copy = umin(txb-\u003espace, msg_data_left(msg));\n+\t\tif (len \u003e 0) {\n+\t\t\tsize_t copy = min3(txb-\u003espace, len, msg_data_left(msg));\n \n \t\t\t_debug(\"add %zu\", copy);\n \t\t\tif (!copy_from_iter_full(txb-\u003edata + txb-\u003eoffset,\n@@ -428,6 +436,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\ttxb-\u003elen += copy;\n \t\t\ttxb-\u003eoffset += copy;\n \t\t\tcopied += copy;\n+\t\t\tlen -= copy;\n \t\t\tif (call-\u003etx_total_len != -1)\n \t\t\t\tcall-\u003etx_total_len -= copy;\n \t\t}\n@@ -439,62 +448,100 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \n \t\t/* add the packet to the send queue if it's now full */\n \t\tif (!txb-\u003espace ||\n-\t\t (msg_data_left(msg) == 0 \u0026\u0026 !more)) {\n-\t\t\tif (msg_data_left(msg) == 0 \u0026\u0026 !more)\n-\t\t\t\ttxb-\u003eflags |= RXRPC_LAST_PACKET;\n-\n+\t\t (len == 0 \u0026\u0026 !more)) {\n+\t\t\t/* Do any required crypto. If this fails, it could\n+\t\t\t * have corrupted the txbuf content with a partial\n+\t\t\t * encrypt. Assume that ENOMEM is retryable, but\n+\t\t\t * everything else is terminal.\n+\t\t\t */\n \t\t\tret = call-\u003esecurity-\u003esecure_packet(call, txb);\n-\t\t\tif (ret \u003c 0)\n-\t\t\t\tgoto out;\n+\t\t\tif (ret \u003c 0) {\n+\t\t\t\t/* Assume that ENOMEM here means that the\n+\t\t\t\t * encryption hasn't happened yet. The data is\n+\t\t\t\t * aligned to avoid the need for slow buffering\n+\t\t\t\t * in the crypto walk.\n+\t\t\t\t */\n+\t\t\t\tif (ret == -ENOMEM)\n+\t\t\t\t\tgoto maybe_error_rewind;\n+\t\t\t\tset_bit(RXRPC_CALL_TX_ERROR, \u0026call-\u003eflags);\n+\t\t\t\tgoto out_txb;\n+\t\t\t}\n+\n+\t\t\tif (len == 0 \u0026\u0026 !more)\n+\t\t\t\ttxb-\u003eflags |= RXRPC_LAST_PACKET;\n \t\t\trxrpc_queue_packet(rx, call, txb, notify_end_tx);\n \t\t\ttxb = NULL;\n \t\t}\n-\t} while (msg_data_left(msg) \u003e 0);\n+\t} while (len \u003e 0 \u0026\u0026 msg_data_left(msg) \u003e 0);\n \n success:\n \tret = copied;\n-\tif (rxrpc_call_is_complete(call) \u0026\u0026\n-\t call-\u003eerror \u003c 0)\n-\t\tret = call-\u003eerror;\n-out:\n+out_txb:\n \tcall-\u003etx_pending = txb;\n+out_unlock:\n+\tmutex_unlock(\u0026call-\u003euser_mutex);\n \t_leave(\" = %d\", ret);\n \treturn ret;\n \n call_terminated:\n \trxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);\n-\t_leave(\" = %d\", call-\u003eerror);\n-\treturn call-\u003eerror;\n-\n+\tcall-\u003etx_pending = NULL;\n+\tret = call-\u003eerror;\n+\tgoto out_unlock;\n+\n+maybe_error_rewind:\n+\t/* If we got a retryable error after copying all the supplied data into\n+\t * the last packet, we need to rewind as much as we can so the caller\n+\t * knows they need to retry the sendmsg.\n+\t */\n+\tif (copied \u0026\u0026 !more \u0026\u0026 !len) {\n+\t\tunsigned int rewind_by = umin(copied, txb-\u003elen);\n+\n+\t\ttxb-\u003espace += rewind_by;\n+\t\ttxb-\u003elen -= rewind_by;\n+\t\ttxb-\u003eoffset -= rewind_by;\n+\t\tcopied -= rewind_by;\n+\t\tif (call-\u003etx_total_len != -1)\n+\t\t\tcall-\u003etx_total_len += rewind_by;\n+\t\tiov_iter_revert(\u0026msg-\u003emsg_iter, rewind_by);\n+\t}\n maybe_error:\n-\tif (copied)\n+\tif (copied) {\n+\t\tif (rxrpc_call_is_complete(call) \u0026\u0026\n+\t\t call-\u003eerror \u003c 0) {\n+\t\t\tret = call-\u003eerror;\n+\t\t\tgoto out_txb;\n+\t\t}\n \t\tgoto success;\n-\tgoto out;\n+\t}\n+\tgoto out_txb;\n \n efault:\n \tret = -EFAULT;\n-\tgoto out;\n+\tgoto out_txb;\n \n wait_for_space:\n \tret = -EAGAIN;\n \tif (msg-\u003emsg_flags \u0026 MSG_DONTWAIT)\n \t\tgoto maybe_error;\n \tmutex_unlock(\u0026call-\u003euser_mutex);\n-\t*_dropped_lock = true;\n+\n \tret = rxrpc_wait_for_tx_window(rx, call, \u0026timeo,\n \t\t\t\t msg-\u003emsg_flags \u0026 MSG_WAITALL);\n \tif (ret \u003c 0)\n-\t\tgoto maybe_error;\n+\t\tgoto out_nolock;\n \tif (call-\u003einterruptibility == RXRPC_INTERRUPTIBLE) {\n \t\tif (mutex_lock_interruptible(\u0026call-\u003euser_mutex) \u003c 0) {\n \t\t\tret = sock_intr_errno(timeo);\n-\t\t\tgoto maybe_error;\n+\t\t\tgoto out_nolock;\n \t\t}\n \t} else {\n \t\tmutex_lock(\u0026call-\u003euser_mutex);\n \t}\n-\t*_dropped_lock = false;\n \tgoto reload;\n+out_nolock:\n+\t_leave(\" = %d [intr]\", ret);\n+\treturn copied ?: ret;\n }\n \n /*\n@@ -660,7 +707,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,\n int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n {\n \tstruct rxrpc_call *call;\n-\tbool dropped_lock = false;\n \tint ret;\n \n \tstruct rxrpc_send_params p = {\n@@ -769,16 +815,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n \t\tret = 0;\n \t\tbreak;\n \tcase RXRPC_CMD_SEND_DATA:\n-\t\tret = rxrpc_send_data(rx, call, msg, len, NULL, \u0026dropped_lock);\n-\t\tbreak;\n+\t\tret = rxrpc_send_data(rx, call, msg, len, NULL);\n+\t\tgoto error_put;\n \tdefault:\n \t\tret = -EINVAL;\n \t\tbreak;\n \t}\n \n out_put_unlock:\n-\tif (!dropped_lock)\n-\t\tmutex_unlock(\u0026call-\u003euser_mutex);\n+\tmutex_unlock(\u0026call-\u003euser_mutex);\n error_put:\n \trxrpc_put_call(call, rxrpc_call_put_sendmsg);\n \t_leave(\" = %d\", ret);\n@@ -800,15 +845,21 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n * Allow a kernel service to send data on a call. The call must be in an state\n * appropriate to sending data. No control data should be supplied in @msg,\n * nor should an address be supplied. MSG_MORE should be flagged if there's\n- * more data to come, otherwise this data will end the transmission phase.\n+ * more data to come, otherwise this data will end the transmission phase if\n+ * all the data is buffered.\n+ *\n+ * Note that this function may return a short send, in which case it should be\n+ * called again for the remainder of the data or to pick up an error that\n+ * caused the short send.\n *\n- * Return: %0 if successful and a negative error code otherwise.\n+ * Return: The number of bytes buffered (could be %0 if @len is 0 or\n+ * msg_iter holds 0 bytes) if successful and a negative error code\n+ * otherwise.\n */\n int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n \t\t\t struct msghdr *msg, size_t len,\n \t\t\t rxrpc_notify_end_tx_t notify_end_tx)\n {\n-\tbool dropped_lock = false;\n \tint ret;\n \n \t_enter(\"{%d},\", call-\u003edebug_id);\n@@ -819,12 +870,10 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n \tmutex_lock(\u0026call-\u003euser_mutex);\n \n \tret = rxrpc_send_data(rxrpc_sk(sock-\u003esk), call, msg, len,\n-\t\t\t notify_end_tx, \u0026dropped_lock);\n+\t\t\t notify_end_tx);\n \tif (ret == -ESHUTDOWN)\n \t\tret = call-\u003eerror;\n \n-\tif (!dropped_lock)\n-\t\tmutex_unlock(\u0026call-\u003euser_mutex);\n \t_leave(\" = %d\", ret);\n \treturn ret;\n }\n"
} |
| 2/1 | 2026/09/07 14:49 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": [
"AF_RXRPC",
"AFS_FS",
"RXGK",
"RXPERF"
],
"FocusSymbols": [
"rxrpc_send_data",
"rxrpc_do_sendmsg",
"rxrpc_kernel_send_data",
"rxrpc_recvmsg",
"rxrpc_notify_socket",
"rxrpc_poke_conn",
"rxrpc_preparse_xdr_yfs_rxgk",
"rxgk_init_connection_security",
"afs_make_call",
"afs_send_simple_reply",
"afs_send_empty_reply",
"afs_create_yfs_cm_token",
"rxperf_process_call"
],
"Reasoning": "The patch modifies RxRPC socket data sending and completion notification mechanisms, connection reference counting, key payload parsing, and in-kernel AFS/rxperf send paths. These changes involve core networking and filesystem state machines and error-handling paths that are fully reachable via AF_RXRPC sockets, keys syscalls, and AFS operations in standard virtualized environments.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 3d3aff233769081693eda889b58aa3203a62892e
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Sep 7 14:49:22 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index 8926dab8e2e60..7df6aff7644c0 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -879,14 +879,21 @@ The kernel interface functions are as follows:
exclusively to in-kernel virtual addresses. msg.msg_flags may be given
MSG_MORE if there will be subsequent data sends for this call.
- The msg must not specify a destination address, control data or any flags
- other than MSG_MORE. len is the total amount of data to transmit.
+ msg must not specify a destination address, control data or any flags
+ other than MSG_MORE. len is the amount of data to add to the
+ transmission. The last-packet flag will only be set on the outgoing
+ packet if MSG_MORE is not set and len amount of bytes are buffered.
notify_end_rx can be NULL or it can be used to specify a function to be
called when the call changes state to end the Tx phase. This function is
called with a spinlock held to prevent the last DATA packet from being
transmitted until the function returns.
+ The function returns the amount of data buffered or an error. It will
+ return zero only if len is 0 or if msg->msg_iter is empty. It may also
+ make a short write, buffering less than the amount of data provided or the
+ len specified, in which case it should be called again.
+
(#) Receive data from a call::
int rxrpc_kernel_recv_data(struct socket *sock,
diff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c
index 103168c70dd4d..5eeeef761cf31 100644
--- a/fs/afs/cm_security.c
+++ b/fs/afs/cm_security.c
@@ -235,7 +235,7 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,
* struct RXGK_AuthName identities<>;
* };
*/
- toksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
+ toksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
offset = 0;
encsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, &offset);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 290873bac89b3..65a0866cd8b85 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1416,22 +1416,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 = afs_get_call(call, afs_call_trace_get);
- 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);
- afs_put_call(call);
-}
-
static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
{
call->iov_len = size;
@@ -1763,6 +1747,23 @@ 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 = afs_get_call(call, afs_call_trace_get);
+ 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);
+ afs_put_call(call);
+}
+
/*
* 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 d82916657a3dd..1f5b6aa689433 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -412,26 +412,32 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
msg.msg_controllen = 0;
msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
- ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
- &msg, call->request_size,
- afs_notify_end_request_tx);
- if (ret < 0)
- goto error_do_abort;
+ do {
+ ret = rxrpc_kernel_send_data(call->net->socket, rxcall, &msg,
+ msg_data_left(&msg),
+ afs_notify_end_request_tx);
+ if (ret < 0)
+ goto error_do_abort;
+ } while (msg_data_left(&msg) > 0);
if (call->write_iter) {
msg.msg_iter = *call->write_iter;
msg.msg_flags &= ~MSG_MORE;
trace_afs_send_data(call, &msg);
- ret = rxrpc_kernel_send_data(call->net->socket,
- call->rxcall, &msg,
- iov_iter_count(&msg.msg_iter),
- afs_notify_end_request_tx);
+ do {
+ ret = rxrpc_kernel_send_data(call->net->socket,
+ call->rxcall, &msg,
+ msg_data_left(&msg),
+ afs_notify_end_request_tx);
+ if (ret < 0) {
+ trace_afs_sent_data(call, &msg, ret);
+ goto error_do_abort;
+ }
+ } while (msg_data_left(&msg) > 0);
*call->write_iter = msg.msg_iter;
- trace_afs_sent_data(call, &msg, ret);
- if (ret < 0)
- goto error_do_abort;
+ trace_afs_sent_data(call, &msg, 0);
}
/* Note that at this point, we may have received the reply or an abort
@@ -443,10 +449,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
return;
error_do_abort:
- if (ret != -ECONNABORTED)
- rxrpc_kernel_abort_call(call->net->socket, rxcall,
- RX_USER_ABORT, ret,
- afs_abort_send_data_error);
+ rxrpc_kernel_abort_call(call->net->socket, rxcall,
+ RX_USER_ABORT, ret, afs_abort_send_data_error);
if (call->async) {
afs_see_call(call, afs_call_trace_async_abort);
return;
@@ -859,6 +863,7 @@ void afs_send_empty_reply(struct afs_call *call)
{
struct afs_net *net = call->net;
struct msghdr msg;
+ int ret;
_enter("");
@@ -871,22 +876,13 @@ void afs_send_empty_reply(struct afs_call *call)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
- afs_notify_end_reply_tx)) {
- case 0:
- _leave(" [replied]");
+ ret = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
+ afs_notify_end_reply_tx);
+ if (ret >= 0) /* Shouldn't buffer more than 0 bytes. */
return;
- case -ENOMEM:
- _debug("oom");
- rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
- fallthrough;
- default:
- _leave(" [error]");
- return;
- }
+ rxrpc_kernel_abort_call(net->socket, call->rxcall,
+ RXGEN_SS_MARSHAL, ret, afs_abort_send_error);
}
/*
@@ -912,20 +908,21 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
- afs_notify_end_reply_tx);
+ do {
+ n = rxrpc_kernel_send_data(net->socket, call->rxcall,
+ &msg, msg_data_left(&msg),
+ afs_notify_end_reply_tx);
+ } while (n >= 0 && msg_data_left(&msg) > 0);
+
if (n >= 0) {
/* Success */
_leave(" [replied]");
return;
}
- if (n == -ENOMEM) {
- _debug("oom");
- rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
- }
+
+ rxrpc_kernel_abort_call(net->socket, call->rxcall,
+ RXGEN_SS_MARSHAL, n, afs_abort_send_error);
_leave(" [error]");
}
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 1b3c48b5591df..04b0bb682b810 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/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 704a10de66700..52f8718cf7250 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -20,16 +20,16 @@
/* AFS errors */ \
EM(afs_abort_general_error, "afs-error") \
EM(afs_abort_interrupted, "afs-intr") \
- EM(afs_abort_oom, "afs-oom") \
EM(afs_abort_op_not_supported, "afs-op-notsupp") \
EM(afs_abort_probeuuid_negative, "afs-probeuuid-neg") \
EM(afs_abort_send_data_error, "afs-send-data") \
+ EM(afs_abort_send_error, "afs-send-error") \
EM(afs_abort_unmarshal_error, "afs-unmarshal") \
EM(afs_abort_unsupported_sec_class, "afs-unsup-sec-class") \
/* rxperf errors */ \
EM(rxperf_abort_general_error, "rxperf-error") \
- EM(rxperf_abort_oom, "rxperf-oom") \
EM(rxperf_abort_op_not_supported, "rxperf-op-notsupp") \
+ EM(rxperf_abort_send_error, "rxperf-send-error") \
EM(rxperf_abort_unmarshal_error, "rxperf-unmarshal") \
/* RxKAD security errors */ \
EM(rxkad_abort_1_short_check, "rxkad1-short-check") \
@@ -148,6 +148,7 @@
EM(rxrpc_eproto_wrong_security, "wrong-sec") \
EM(rxrpc_recvmsg_excess_data, "recvmsg-excess") \
EM(rxrpc_recvmsg_short_data, "recvmsg-short") \
+ EM(rxrpc_sendmsg_tx_error, "tx-error") \
E_(rxrpc_sendmsg_late_send, "sendmsg-late")
#define rxrpc_call_poke_traces \
@@ -342,6 +343,7 @@
EM(rxrpc_call_see_distribute_error, "SEE dist-err") \
EM(rxrpc_call_see_input, "SEE input ") \
EM(rxrpc_call_see_notify_released, "SEE nfy-rlsd") \
+ EM(rxrpc_call_see_notify_skipped, "SEE nfy-skip") \
EM(rxrpc_call_see_recvmsg, "SEE recvmsg ") \
EM(rxrpc_call_see_recvmsg_requeue, "SEE recv-rqu") \
EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 865f05fe37ab9..cb36a709f540e 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -642,6 +642,7 @@ enum rxrpc_call_flag {
RXRPC_CALL_TX_LAST, /* Last packet in Tx buffer (at rxtx_top) */
RXRPC_CALL_TX_ALL_ACKED, /* Last packet has been hard-acked */
RXRPC_CALL_TX_NO_MORE, /* No more data to transmit (MSG_MORE deasserted) */
+ RXRPC_CALL_TX_ERROR, /* Terminal error; call needs abort */
RXRPC_CALL_SEND_PING, /* A ping will need to be sent */
RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */
RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */
@@ -1109,6 +1110,7 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
/*
* call_state.c
*/
+void rxrpc_notify_socket(struct rxrpc_call *call);
bool rxrpc_set_call_completion(struct rxrpc_call *call,
enum rxrpc_call_completion compl,
u32 abort_code,
@@ -1441,7 +1443,6 @@ extern const struct seq_operations rxrpc_local_seq_ops;
/*
* recvmsg.c
*/
-void rxrpc_notify_socket(struct rxrpc_call *);
int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
/*
diff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c
index 6afb54373ebbf..364810c652766 100644
--- a/net/rxrpc/call_state.c
+++ b/net/rxrpc/call_state.c
@@ -7,6 +7,60 @@
#include "ar-internal.h"
+/*
+ * Post a call for attention by the socket or kernel service.
+ */
+static void __rxrpc_notify_socket(struct rxrpc_call *call)
+{
+ struct rxrpc_sock *rx;
+ struct sock *sk;
+ unsigned long flags;
+
+ if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
+ rxrpc_see_call(call, rxrpc_call_see_notify_released);
+ return;
+ }
+
+ rcu_read_lock();
+
+ rx = rcu_dereference(call->socket);
+ sk = &rx->sk;
+ if (rx && sk->sk_state < RXRPC_CLOSE) {
+ if (call->notify_rx) {
+ spin_lock_irqsave(&call->notify_lock, flags);
+ call->notify_rx(sk, call, call->user_call_ID);
+ spin_unlock_irqrestore(&call->notify_lock, flags);
+ } else {
+ spin_lock_irqsave(&rx->recvmsg_lock, flags);
+ if (list_empty(&call->recvmsg_link)) {
+ rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+ list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+ }
+ spin_unlock_irqrestore(&rx->recvmsg_lock, flags);
+
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ _debug("call %ps", sk->sk_data_ready);
+ sk->sk_data_ready(sk);
+ }
+ }
+ }
+
+ rcu_read_unlock();
+}
+
+/*
+ * Post a call for attention by the socket or kernel service.
+ */
+void rxrpc_notify_socket(struct rxrpc_call *call)
+{
+ if (rxrpc_call_is_complete(call)) {
+ rxrpc_see_call(call, rxrpc_call_see_notify_skipped);
+ return;
+ }
+
+ __rxrpc_notify_socket(call);
+}
+
/*
* Transition a call to the complete state.
*/
@@ -25,7 +79,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,
rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
trace_rxrpc_call_complete(call);
wake_up(&call->waitq);
- rxrpc_notify_socket(call);
+ __rxrpc_notify_socket(call);
return true;
}
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0ece717db0f85..1be50e0c9cee5 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -34,7 +34,10 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
spin_lock_irq(&local->lock);
busy = !list_empty(&conn->attend_link);
if (!busy) {
- rxrpc_get_connection(conn, why);
+ if (!rxrpc_get_connection_maybe(conn, why)) {
+ spin_unlock_irq(&local->lock);
+ return;
+ }
list_add_tail(&conn->attend_link, &local->conn_attend_q);
}
spin_unlock_irq(&local->lock);
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index a0aa78d892897..30d6db052c216 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -172,6 +172,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
const __be32 *ticket, *key;
s64 tmp;
size_t raw_keylen, raw_tktlen, keylen, tktlen;
+ int ret = -EKEYREJECTED;
_enter(",{%x,%x,%x,%x},%x",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -229,6 +230,11 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
token->rxgk->key.data = token->rxgk->_key;
token->rxgk->ticket.len = raw_tktlen;
+ if (!crypto_krb5_find_enctype(token->rxgk->enctype)) {
+ ret = -ENOPKG;
+ goto reject_token;
+ }
+
if (token->rxgk->endtime != 0) {
expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
if (expiry < 0)
@@ -280,7 +286,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
kfree(token->rxgk);
kfree(token);
reject:
- return -EKEYREJECTED;
+ return ret;
expired:
kfree(token->rxgk);
kfree(token);
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index efcba4b2e74f0..28b2148b56936 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -17,13 +17,12 @@
#include "ar-internal.h"
/*
- * Post a call for attention by the socket or kernel service. Further
- * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ * Requeue a call for recvmsg() to pick up.
*/
-void rxrpc_notify_socket(struct rxrpc_call *call)
+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)
{
- struct rxrpc_sock *rx;
- struct sock *sk;
+ struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+ struct sock *sk = &rx->sk;
_enter("%d", call->debug_id);
@@ -32,31 +31,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
return;
}
- rcu_read_lock();
-
- rx = rcu_dereference(call->socket);
- sk = &rx->sk;
- if (rx && sk->sk_state < RXRPC_CLOSE) {
- if (call->notify_rx) {
- spin_lock_irq(&call->notify_lock);
- call->notify_rx(sk, call, call->user_call_ID);
- spin_unlock_irq(&call->notify_lock);
- } else {
- spin_lock_irq(&rx->recvmsg_lock);
- if (list_empty(&call->recvmsg_link)) {
- rxrpc_get_call(call, rxrpc_call_get_notify_socket);
- list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
- }
- spin_unlock_irq(&rx->recvmsg_lock);
+ spin_lock_irq(&rx->recvmsg_lock);
+ if (list_empty(&call->recvmsg_link)) {
+ rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+ list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+ }
+ spin_unlock_irq(&rx->recvmsg_lock);
- if (!sock_flag(sk, SOCK_DEAD)) {
- _debug("call %ps", sk->sk_data_ready);
- sk->sk_data_ready(sk);
- }
- }
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ _debug("call %ps", sk->sk_data_ready);
+ sk->sk_data_ready(sk);
}
- rcu_read_unlock();
_leave("");
}
@@ -561,7 +547,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (!(flags & MSG_PEEK) &&
!skb_queue_empty(&call->recvmsg_queue))
- rxrpc_notify_socket(call);
+ rxrpc_requeue_call(sock, call);
goto not_yet_complete;
call_failed:
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 77a67ace1d248..b49221f57f677 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -251,8 +251,10 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
GFP_NOFS);
if (IS_ERR(gk))
return PTR_ERR(gk);
+ write_lock(&conn->security_use_lock);
conn->rxgk.enctype = gk->krb5->etype;
conn->rxgk.keys[gk->key_number & 3] = gk;
+ write_unlock(&conn->security_use_lock);
switch (conn->security_level) {
case RXRPC_SECURITY_PLAIN:
diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
index b8df6d22314d6..ebd54222c64ef 100644
--- a/net/rxrpc/rxperf.c
+++ b/net/rxrpc/rxperf.c
@@ -538,15 +538,18 @@ static int rxperf_process_call(struct rxperf_call *call)
iov[0].iov_len = len;
iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
msg.msg_flags = 0;
- n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg, len,
- rxperf_notify_end_reply_tx);
+ do {
+ n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall,
+ &msg, msg_data_left(&msg),
+ rxperf_notify_end_reply_tx);
+ } while (n >= 0 && msg_data_left(&msg) > 0);
+
if (n >= 0)
return 0; /* Success */
- if (n == -ENOMEM)
- rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- rxperf_abort_oom);
+ rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
+ RXGEN_SS_MARSHAL, n,
+ rxperf_abort_send_error);
return n;
}
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index ed2c9a51005ad..8bb327dc2833e 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -320,8 +320,8 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)
static int rxrpc_send_data(struct rxrpc_sock *rx,
struct rxrpc_call *call,
struct msghdr *msg, size_t len,
- rxrpc_notify_end_tx_t notify_end_tx,
- bool *_dropped_lock)
+ rxrpc_notify_end_tx_t notify_end_tx)
+ __releases(&call->user_mutex)
{
struct rxrpc_txbuf *txb;
struct sock *sk = &rx->sk;
@@ -330,29 +330,37 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
bool more = msg->msg_flags & MSG_MORE;
int ret, copied = 0;
- if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
- trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
- call->cid, call->call_id, call->rx_consumed,
- 0, -EPROTO);
- return -EPROTO;
- }
-
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
ret = rxrpc_wait_to_be_connected(call, &timeo);
if (ret < 0)
- return ret;
+ goto out_unlock;
if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
ret = rxrpc_init_client_conn_security(call->conn);
if (ret < 0)
- return ret;
+ goto out_unlock;
}
/* this should be in poll */
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
reload:
+ if (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags))) {
+ trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
+ call->cid, call->call_id, call->rx_consumed,
+ 0, -EPROTO);
+ ret = -EPROTO;
+ goto maybe_error;
+ }
+ if (unlikely(test_bit(RXRPC_CALL_TX_ERROR, &call->flags))) {
+ trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_tx_error,
+ call->cid, call->call_id, call->rx_consumed,
+ 0, -EIO);
+ ret = -EIO;
+ goto maybe_error;
+ }
+
txb = call->tx_pending;
call->tx_pending = NULL;
if (txb)
@@ -379,9 +387,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = -EMSGSIZE;
if (call->tx_total_len != -1) {
- if (len - copied > call->tx_total_len)
+ if (len > call->tx_total_len)
goto maybe_error;
- if (!more && len - copied != call->tx_total_len)
+ if (!more && len != call->tx_total_len)
goto maybe_error;
}
@@ -405,7 +413,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
* the security header is going to be in the padded
* region (enc blocksize), but the trailer is not.
*/
- remain = more ? INT_MAX : msg_data_left(msg);
+ remain = more ? INT_MAX : len;
txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation);
if (!txb) {
ret = -ENOMEM;
@@ -416,8 +424,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
_debug("append");
/* append next segment of data to the current buffer */
- if (msg_data_left(msg) > 0) {
- size_t copy = umin(txb->space, msg_data_left(msg));
+ if (len > 0) {
+ size_t copy = min3(txb->space, len, msg_data_left(msg));
_debug("add %zu", copy);
if (!copy_from_iter_full(txb->data + txb->offset,
@@ -428,6 +436,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
txb->len += copy;
txb->offset += copy;
copied += copy;
+ len -= copy;
if (call->tx_total_len != -1)
call->tx_total_len -= copy;
}
@@ -439,62 +448,100 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
/* add the packet to the send queue if it's now full */
if (!txb->space ||
- (msg_data_left(msg) == 0 && !more)) {
- if (msg_data_left(msg) == 0 && !more)
- txb->flags |= RXRPC_LAST_PACKET;
-
+ (len == 0 && !more)) {
+ /* Do any required crypto. If this fails, it could
+ * have corrupted the txbuf content with a partial
+ * encrypt. Assume that ENOMEM is retryable, but
+ * everything else is terminal.
+ */
ret = call->security->secure_packet(call, txb);
- if (ret < 0)
- goto out;
+ if (ret < 0) {
+ /* Assume that ENOMEM here means that the
+ * encryption hasn't happened yet. The data is
+ * aligned to avoid the need for slow buffering
+ * in the crypto walk.
+ */
+ if (ret == -ENOMEM)
+ goto maybe_error_rewind;
+ set_bit(RXRPC_CALL_TX_ERROR, &call->flags);
+ goto out_txb;
+ }
+
+ if (len == 0 && !more)
+ txb->flags |= RXRPC_LAST_PACKET;
rxrpc_queue_packet(rx, call, txb, notify_end_tx);
txb = NULL;
}
- } while (msg_data_left(msg) > 0);
+ } while (len > 0 && msg_data_left(msg) > 0);
success:
ret = copied;
- if (rxrpc_call_is_complete(call) &&
- call->error < 0)
- ret = call->error;
-out:
+out_txb:
call->tx_pending = txb;
+out_unlock:
+ mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
call_terminated:
rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
- _leave(" = %d", call->error);
- return call->error;
-
+ call->tx_pending = NULL;
+ ret = call->error;
+ goto out_unlock;
+
+maybe_error_rewind:
+ /* If we got a retryable error after copying all the supplied data into
+ * the last packet, we need to rewind as much as we can so the caller
+ * knows they need to retry the sendmsg.
+ */
+ if (copied && !more && !len) {
+ unsigned int rewind_by = umin(copied, txb->len);
+
+ txb->space += rewind_by;
+ txb->len -= rewind_by;
+ txb->offset -= rewind_by;
+ copied -= rewind_by;
+ if (call->tx_total_len != -1)
+ call->tx_total_len += rewind_by;
+ iov_iter_revert(&msg->msg_iter, rewind_by);
+ }
maybe_error:
- if (copied)
+ if (copied) {
+ if (rxrpc_call_is_complete(call) &&
+ call->error < 0) {
+ ret = call->error;
+ goto out_txb;
+ }
goto success;
- goto out;
+ }
+ goto out_txb;
efault:
ret = -EFAULT;
- goto out;
+ goto out_txb;
wait_for_space:
ret = -EAGAIN;
if (msg->msg_flags & MSG_DONTWAIT)
goto maybe_error;
mutex_unlock(&call->user_mutex);
- *_dropped_lock = true;
+
ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
msg->msg_flags & MSG_WAITALL);
if (ret < 0)
- goto maybe_error;
+ goto out_nolock;
if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
if (mutex_lock_interruptible(&call->user_mutex) < 0) {
ret = sock_intr_errno(timeo);
- goto maybe_error;
+ goto out_nolock;
}
} else {
mutex_lock(&call->user_mutex);
}
- *_dropped_lock = false;
goto reload;
+out_nolock:
+ _leave(" = %d [intr]", ret);
+ return copied ?: ret;
}
/*
@@ -660,7 +707,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
{
struct rxrpc_call *call;
- bool dropped_lock = false;
int ret;
struct rxrpc_send_params p = {
@@ -769,16 +815,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
ret = 0;
break;
case RXRPC_CMD_SEND_DATA:
- ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
- break;
+ ret = rxrpc_send_data(rx, call, msg, len, NULL);
+ goto error_put;
default:
ret = -EINVAL;
break;
}
out_put_unlock:
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
+ mutex_unlock(&call->user_mutex);
error_put:
rxrpc_put_call(call, rxrpc_call_put_sendmsg);
_leave(" = %d", ret);
@@ -800,15 +845,21 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
* Allow a kernel service to send data on a call. The call must be in an state
* appropriate to sending data. No control data should be supplied in @msg,
* nor should an address be supplied. MSG_MORE should be flagged if there's
- * more data to come, otherwise this data will end the transmission phase.
+ * more data to come, otherwise this data will end the transmission phase if
+ * all the data is buffered.
+ *
+ * Note that this function may return a short send, in which case it should be
+ * called again for the remainder of the data or to pick up an error that
+ * caused the short send.
*
- * Return: %0 if successful and a negative error code otherwise.
+ * Return: The number of bytes buffered (could be %0 if @len is 0 or
+ * msg_iter holds 0 bytes) if successful and a negative error code
+ * otherwise.
*/
int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
struct msghdr *msg, size_t len,
rxrpc_notify_end_tx_t notify_end_tx)
{
- bool dropped_lock = false;
int ret;
_enter("{%d},", call->debug_id);
@@ -819,12 +870,10 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
mutex_lock(&call->user_mutex);
ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
- notify_end_tx, &dropped_lock);
+ notify_end_tx);
if (ret == -ESHUTDOWN)
ret = call->error;
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
}
|
| 3/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 14135 output: 40 thoughts: 909 Thoughts: **Fuzzing Feasibility Analysis: RXRPC Patch** Okay, let's dive into this patch and figure out if it's fuzz-worthy, what the ideal configuration looks like, and what symbols we should target. First, I need to get a handle on the scope of the code modifications. From what I can tell, we have: 1. Documentation updates, not terribly interesting from a fuzzing perspective, but good to know they're there. 2. A buffer size fix in `afs_create_yfs_cm_token`. That's a classic target, so we'll need to keep that in mind for coverage. 3. Some server assignment updates in `afs_make_op_call`. 4. Significant changes in the RXRPC code: `afs_make_call`, `afs_send_empty_reply`, and `afs_send_simple_reply` all have new loops around `rxrpc_kernel_send_data` with updated error handling. This could be where the interesting bugs lie, especially around error conditions. 5. Tracepoint additions. Useful for debugging but not directly fuzz-relevant. 6. Declarations and flags in `ar-internal.h`, including `RXRPC_CALL_TX_ERROR`. Need to understand the new error flags. 7. Updates to call state management in `call_state.c`. 8. A connection poking operation using `rxrpc_get_connection_maybe`. 9. Crypto validation in `rxrpc_preparse_xdr_yfs_rxgk`, now validating the crypto enctype. This is intriguing, might lead to some interesting crypto-related bugs. 10. Requeue and receive message handling. 11. Security locking in `rxgk_init_connection_security`. 12. Looping `rxrpc_kernel_send_data` in `rxperf_process_call`. 13. The big one: `sendmsg.c`. Major rewrite of send logic, focusing on error handling, length checks, and locking. This is definitely a prime target. The use of `RXRPC_CALL_TX_ERROR`, `msg_data_left`, `copy_from_iter_full`, `min3`, and `rxrpc_wait_for_tx_window` all indicate complex logic. Now, the crucial question: can we reach these changes in a standard fuzzing environment like QEMU or GCE? Thankfully, AF\_RXRPC is a network socket family, and AFS is an in-kernel filesystem. Syzkaller regularly fuzzez AF\_RXRPC, and we have in-kernel filesystems that make use of the protocol. We can access AF\_RXRPC through standard syscalls, and key ring operations are also accessible. This is **heavily** reachable code within the networking and filesystems subsystems, making `WorthFuzzing` a resounding `true`. Now, I'll use `grepper` to determine the Kconfig requirements for AF\_RXRPC, AFS, RXGK, and crypto\_krb5 (just in case they're relevant). Let's nail down those configurations so we can optimize our setup. |
| 4/2 | 2026/09/07 14:49 | tool | grepper |
0mArgs:{
"Expression": "config (AF_RXRPC|AFS_FS|RXGK)",
"PathPrefix": "net/rxrpc/"
}Results: {
"Output": "net/rxrpc/Kconfig-5-\nnet/rxrpc/Kconfig:6:config AF_RXRPC\nnet/rxrpc/Kconfig-7-\ttristate \"RxRPC session sockets\"\n--\nnet/rxrpc/Kconfig=25=if AF_RXRPC\nnet/rxrpc/Kconfig-26-\nnet/rxrpc/Kconfig:27:config AF_RXRPC_IPV6\nnet/rxrpc/Kconfig-28-\tbool \"IPv6 support for RxRPC\"\n--\nnet/rxrpc/Kconfig-33-\nnet/rxrpc/Kconfig:34:config AF_RXRPC_INJECT_LOSS\nnet/rxrpc/Kconfig-35-\tbool \"Inject packet loss into RxRPC packet stream\"\n--\nnet/rxrpc/Kconfig-39-\nnet/rxrpc/Kconfig:40:config AF_RXRPC_INJECT_RX_DELAY\nnet/rxrpc/Kconfig-41-\tbool \"Inject delay into packet reception\"\n--\nnet/rxrpc/Kconfig-49-\nnet/rxrpc/Kconfig:50:config AF_RXRPC_DEBUG\nnet/rxrpc/Kconfig-51-\tbool \"RxRPC dynamic debugging\"\n--\nnet/rxrpc/Kconfig=58=config RXKAD\n--\nnet/rxrpc/Kconfig-65-\nnet/rxrpc/Kconfig:66:config RXGK\nnet/rxrpc/Kconfig-67-\tbool \"RxRPC GSSAPI security\"\n--\nnet/rxrpc/Kconfig=89=config RXPERF\n--\nnet/rxrpc/Kconfig-95-\nnet/rxrpc/Kconfig:96:config AF_RXRPC_KUNIT_TEST\nnet/rxrpc/Kconfig-97-\ttristate \"RxRPC crypto KUnit test\" if !KUNIT_ALL_TESTS\n"
} |
| 5/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 16244 output: 32 thoughts: 24 Thoughts: Here's my summary, as if I were thinking these thoughts: **Examining Configuration Options** Right, let's dive into the details. I need to refresh my memory on the configuration settings for these subsystems. I'll start by checking out the `fs/afs/Kconfig` file. I need to understand what's enabled, what dependencies exist, and how the various options interrelate within the AFS file system implementation. Then, I should head over to `net/rxrpc/Kconfig` and repeat the process for the RxRPC network protocol. Understanding the dependencies and configuration interactions between these two areas, if there are any, is paramount. I need to ensure everything is appropriately configured and that the overall build is clean. This is standard operating procedure, especially when dealing with potentially complex kernel modules. |
| 6/2 | 2026/09/07 14:49 | tool | read-file |
0mArgs:{
"File": "fs/afs/Kconfig",
"FirstLine": 1,
"LineCount": 50
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\tconfig AFS_FS\n 3:\t\ttristate \"Andrew File System support (AFS)\"\n 4:\t\tdepends on INET\n 5:\t\tselect AF_RXRPC\n 6:\t\tselect DNS_RESOLVER\n 7:\t\tselect NETFS_SUPPORT\n 8:\t\tselect CRYPTO_KRB5\n 9:\t\thelp\n 10:\t\t If you say Y here, you will get an experimental Andrew File System\n 11:\t\t driver. It currently only supports unsecured read-only AFS access.\n 12:\t\n 13:\t\t See \u003cfile:Documentation/filesystems/afs.rst\u003e for more information.\n 14:\t\n 15:\t\t If unsure, say N.\n 16:\t\n 17:\tconfig AFS_DEBUG\n 18:\t\tbool \"AFS dynamic debugging\"\n 19:\t\tdepends on AFS_FS\n 20:\t\thelp\n 21:\t\t Say Y here to make runtime controllable debugging messages appear.\n 22:\t\n 23:\t\t See \u003cfile:Documentation/filesystems/afs.rst\u003e for more information.\n 24:\t\n 25:\t\t If unsure, say N.\n 26:\t\n 27:\tconfig AFS_FSCACHE\n 28:\t\tbool \"Provide AFS client caching support\"\n 29:\t\tdepends on AFS_FS=m \u0026\u0026 FSCACHE || AFS_FS=y \u0026\u0026 FSCACHE=y\n 30:\t\thelp\n 31:\t\t Say Y here if you want AFS data to be cached locally on disk through\n 32:\t\t the generic filesystem cache manager\n 33:\t\n 34:\tconfig AFS_DEBUG_CURSOR\n 35:\t\tbool \"AFS server cursor debugging\"\n 36:\t\tdepends on AFS_FS\n 37:\t\thelp\n 38:\t\t Say Y here to cause the contents of a server cursor to be dumped to\n 39:\t\t the dmesg log if the server rotation algorithm fails to successfully\n 40:\t\t contact a server.\n 41:\t\n 42:\t\t See \u003cfile:Documentation/filesystems/afs.rst\u003e for more information.\n 43:\t\n 44:\t\t If unsure, say N.\n"
} |
| 7/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 17050 output: 34 thoughts: 30 Thoughts: Here's my thought process, as if I were considering this myself: **Investigating RXRPC Configuration Dependencies** Okay, so I need to figure out the Kconfig dependencies for RXGK, RXPERF, and AF_RXRPC. It's time to dive into the `net/rxrpc/Kconfig` file. I'm thinking I'll need to check the relationships defined there to see which features are required for these pieces to be enabled, and what the potential build options or dependencies are. Hopefully, it's straightforward, and I can quickly map the dependencies. I expect there might be some interplay between the different components, so I need to see how they're connected within the kernel's build system. Let's get to it. |
| 8/2 | 2026/09/07 14:49 | tool | read-file |
0mArgs:{
"File": "net/rxrpc/Kconfig",
"FirstLine": 1,
"LineCount": 100
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t#\n 3:\t# RxRPC session sockets\n 4:\t#\n 5:\t\n 6:\tconfig AF_RXRPC\n 7:\t\ttristate \"RxRPC session sockets\"\n 8:\t\tdepends on INET\n 9:\t\tselect CRYPTO\n 10:\t\tselect CRYPTO_LIB_DES if RXKAD\n 11:\t\tselect KEYS\n 12:\t\tselect NET_UDP_TUNNEL\n 13:\t\thelp\n 14:\t\t Say Y or M here to include support for RxRPC session sockets (just\n 15:\t\t the transport part, not the presentation part: (un)marshalling is\n 16:\t\t left to the application).\n 17:\t\n 18:\t\t These are used for AFS kernel filesystem and userspace utilities.\n 19:\t\n 20:\t\t This module at the moment only supports client operations and is\n 21:\t\t currently incomplete.\n 22:\t\n 23:\t\t See Documentation/networking/rxrpc.rst.\n 24:\t\n 25:\tif AF_RXRPC\n 26:\t\n 27:\tconfig AF_RXRPC_IPV6\n 28:\t\tbool \"IPv6 support for RxRPC\"\n 29:\t\tdepends on IPV6\n 30:\t\thelp\n 31:\t\t Say Y here to allow AF_RXRPC to use IPV6 UDP as well as IPV4 UDP as\n 32:\t\t its network transport.\n 33:\t\n 34:\tconfig AF_RXRPC_INJECT_LOSS\n 35:\t\tbool \"Inject packet loss into RxRPC packet stream\"\n 36:\t\thelp\n 37:\t\t Say Y here to inject packet loss by discarding some received and some\n 38:\t\t transmitted packets.\n 39:\t\n 40:\tconfig AF_RXRPC_INJECT_RX_DELAY\n 41:\t\tbool \"Inject delay into packet reception\"\n 42:\t\tdepends on SYSCTL\n 43:\t\thelp\n 44:\t\t Say Y here to inject a delay into packet reception, allowing an\n 45:\t\t extended RTT time to be modelled. The delay can be configured using\n 46:\t\t /proc/sys/net/rxrpc/rxrpc_inject_rx_delay, setting a number of\n 47:\t\t milliseconds up to 0.5s (note that the granularity is actually in\n 48:\t\t jiffies).\n 49:\t\n 50:\tconfig AF_RXRPC_DEBUG\n 51:\t\tbool \"RxRPC dynamic debugging\"\n 52:\t\thelp\n 53:\t\t Say Y here to make runtime controllable debugging messages appear.\n 54:\t\n 55:\t\t See Documentation/networking/rxrpc.rst.\n 56:\t\n 57:\t\n 58:\tconfig RXKAD\n 59:\t\tbool \"RxRPC Kerberos security\"\n 60:\t\thelp\n 61:\t\t Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC\n 62:\t\t through the use of the key retention service.\n 63:\t\n 64:\t\t See Documentation/networking/rxrpc.rst.\n 65:\t\n 66:\tconfig RXGK\n 67:\t\tbool \"RxRPC GSSAPI security\"\n 68:\t\tselect CRYPTO_KRB5\n 69:\t\tselect CRYPTO_MANAGER\n 70:\t\tselect CRYPTO_KRB5ENC\n 71:\t\tselect CRYPTO_AUTHENC\n 72:\t\tselect CRYPTO_SKCIPHER\n 73:\t\tselect CRYPTO_HASH_INFO\n 74:\t\tselect CRYPTO_HMAC\n 75:\t\tselect CRYPTO_CMAC\n 76:\t\tselect CRYPTO_SHA1\n 77:\t\tselect CRYPTO_SHA256\n 78:\t\tselect CRYPTO_SHA512\n 79:\t\tselect CRYPTO_CBC\n 80:\t\tselect CRYPTO_CTS\n 81:\t\tselect CRYPTO_AES\n 82:\t\tselect CRYPTO_CAMELLIA\n 83:\t\thelp\n 84:\t\t Provide the GSSAPI-based RxGK security class for AFS. Keys are added\n 85:\t\t with add_key().\n 86:\t\n 87:\t\t See Documentation/networking/rxrpc.rst.\n 88:\t\n 89:\tconfig RXPERF\n 90:\t\ttristate \"RxRPC test service\"\n 91:\t\thelp\n 92:\t\t Provide an rxperf service tester. This listens on UDP port 7009 for\n 93:\t\t incoming calls from the rxperf program (an example of which can be\n 94:\t\t found in OpenAFS).\n 95:\t\n 96:\tconfig AF_RXRPC_KUNIT_TEST\n 97:\t\ttristate \"RxRPC crypto KUnit test\" if !KUNIT_ALL_TESTS\n 98:\t\tdepends on KUNIT \u0026\u0026 RXKAD\n 99:\t\tdefault KUNIT_ALL_TESTS\n 100:\t\thelp\n"
} |
| 9/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 18567 output: 32 thoughts: 174 Thoughts: **My Initial Assessment of the Patch's Scope** Okay, so this patch is clearly making some significant changes. I need to get a handle on the breadth of its impact before I dig in. The initial indicators are pointing to a few key areas that are going to demand my attention: * **`AF_RXRPC`:** This is the core RxRPC protocol, and the patch has landed in several files within its implementation: `sendmsg.c`, `call_state.c`, `conn_object.c`, `key.c`, and `recvmsg.c`. That's a lot of the critical infrastructure. I'll need to scrutinize how those message interactions, call state management, connection objects and key handling, and the receive side are being affected. * **`AFS_FS`:** The `fs/afs/` directory is another critical signal. It seems like the patch's touch to `cm_security.c`, `internal.h`, and `rxrpc.c` may relate to the AFS filesytem's interaction with the RPC implementation. I need to see if we're dealing with some underlying security configuration or the interactions with AFS client tools. * **`RXGK`:** The `RXGK` files within `net/rxrpc/` are a signal as well. It looks like `rxgk.c`, the keying implementations are getting an update. I'm especially interested in `rxrpc_preparse_xdr_yfs_rxgk` because it may involve how the RPC and RXGK work with an outside application layer. * **`RXPERF`:** The `rxperf.c` file is good as well. It may have performance implications on RXRPC. Now, I'm going to quickly check the `Makefile` in the relevant directories, namely `net/rxrpc/` and `fs/afs/`, to ensure I haven't missed anything. I'm expecting to find out if there are any other configurations or dependencies that this patch touches. |
| 10/2 | 2026/09/07 14:49 | tool | read-file |
0mArgs:{
"File": "net/rxrpc/Makefile",
"FirstLine": 1,
"LineCount": 40
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0\n 2:\t#\n 3:\t# Makefile for Linux kernel RxRPC\n 4:\t#\n 5:\t\n 6:\tobj-$(CONFIG_AF_RXRPC) += rxrpc.o\n 7:\t\n 8:\trxrpc-y := \\\n 9:\t\taf_rxrpc.o \\\n 10:\t\tcall_accept.o \\\n 11:\t\tcall_event.o \\\n 12:\t\tcall_object.o \\\n 13:\t\tcall_state.o \\\n 14:\t\tconn_client.o \\\n 15:\t\tconn_event.o \\\n 16:\t\tconn_object.o \\\n 17:\t\tconn_service.o \\\n 18:\t\tinput.o \\\n 19:\t\tinput_rack.o \\\n 20:\t\tinsecure.o \\\n 21:\t\tio_thread.o \\\n 22:\t\tkey.o \\\n 23:\t\tlocal_event.o \\\n 24:\t\tlocal_object.o \\\n 25:\t\tmisc.o \\\n 26:\t\tnet_ns.o \\\n 27:\t\toob.o \\\n 28:\t\toutput.o \\\n 29:\t\tpeer_event.o \\\n 30:\t\tpeer_object.o \\\n 31:\t\trecvmsg.o \\\n 32:\t\trtt.o \\\n 33:\t\tsecurity.o \\\n 34:\t\tsendmsg.o \\\n 35:\t\tserver_key.o \\\n 36:\t\tskbuff.o \\\n 37:\t\ttxbuf.o \\\n 38:\t\tutils.o\n 39:\t\n 40:\trxrpc-$(CONFIG_PROC_FS) += proc.o\n"
} |
| 11/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 19673 output: 33 thoughts: 15 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving Back into the `net/rxrpc/Makefile`** Okay, so we've addressed that initial issue, but there's always more lurking. Time to get back into the nitty-gritty of `net/rxrpc/Makefile`. We can't just fix one thing and call it a day, not in a complex system like this. It's time to thoroughly review the rest of it. This isn't just about spotting obvious errors; I need to scrutinize the dependencies, the build flags, the linking process... everything. Are there any subtle interactions that might cause problems down the line? Are there any optimizations we can implement? Any redundancies we can eliminate? I'm going to look for potential vulnerabilities, areas where future changes could introduce regressions, or opportunities to improve build performance. It's a comprehensive audit, ensuring this critical piece of our infrastructure is as robust and efficient as possible. The devil is in the details, and I intend to find him. Let's see what gems we can dig up. |
| 12/2 | 2026/09/07 14:49 | tool | read-file |
0mArgs:{
"File": "net/rxrpc/Makefile",
"FirstLine": 41,
"LineCount": 40
}Results: {
"Contents": " 41:\trxrpc-$(CONFIG_RXKAD) += rxkad.o fcrypt.o\n 42:\trxrpc-$(CONFIG_SYSCTL) += sysctl.o\n 43:\trxrpc-$(CONFIG_RXGK) += \\\n 44:\t\trxgk.o \\\n 45:\t\trxgk_app.o \\\n 46:\t\trxgk_kdf.o\n 47:\t\n 48:\tobj-$(CONFIG_RXPERF) += rxperf.o\n 49:\tobj-$(CONFIG_KUNIT) += tests/\n"
} |
| 13/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 20114 output: 31 thoughts: 11 Thoughts: Here's a summary of my immediate thought process, expressed in the first person, assuming I'm deep in the weeds of kernel development: **Initial Checkpoint: Diving into the Filesystem Landscape** Alright, time to dig in. The problem's likely filesystem-related, so my first instinct is to zero in on `fs/afs/Makefile`. That's where the AFS-specific build configuration and dependencies live. I need to understand how AFS is being built, linked, and integrated with the rest of the kernel. This `Makefile` will reveal the key components: object files, libraries, include paths, any special flags or defines specific to the AFS implementation. Knowing these will get me one step closer to isolating the relevant code paths and understanding the overall build strategy. I need to quickly identify if there are any obvious misconfigurations, missing dependencies, or conflicting flags that might be contributing to the problem I'm trying to solve. |
| 14/2 | 2026/09/07 14:49 | tool | read-file |
0mArgs:{
"File": "fs/afs/Makefile",
"FirstLine": 1,
"LineCount": 40
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0\n 2:\t#\n 3:\t# Makefile for Red Hat Linux AFS client.\n 4:\t#\n 5:\t\n 6:\tkafs-y := \\\n 7:\t\taddr_list.o \\\n 8:\t\taddr_prefs.o \\\n 9:\t\tcallback.o \\\n 10:\t\tcell.o \\\n 11:\t\tcm_security.o \\\n 12:\t\tcmservice.o \\\n 13:\t\tdir.o \\\n 14:\t\tdir_edit.o \\\n 15:\t\tdir_search.o \\\n 16:\t\tdir_silly.o \\\n 17:\t\tdynroot.o \\\n 18:\t\tfile.o \\\n 19:\t\tflock.o \\\n 20:\t\tfsclient.o \\\n 21:\t\tfs_operation.o \\\n 22:\t\tfs_probe.o \\\n 23:\t\tinode.o \\\n 24:\t\tmain.o \\\n 25:\t\tmisc.o \\\n 26:\t\tmntpt.o \\\n 27:\t\trotate.o \\\n 28:\t\trxrpc.o \\\n 29:\t\tsecurity.o \\\n 30:\t\tserver.o \\\n 31:\t\tserver_list.o \\\n 32:\t\tsuper.o \\\n 33:\t\tsymlink.o \\\n 34:\t\tvalidation.o \\\n 35:\t\tvlclient.o \\\n 36:\t\tvl_alias.o \\\n 37:\t\tvl_list.o \\\n 38:\t\tvl_probe.o \\\n 39:\t\tvl_rotate.o \\\n 40:\t\tvolume.o \\\n"
} |
| 15/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 20798 output: 32 thoughts: 17 Thoughts: Here's my summary, as I see it: **Digging into the `fs/afs/Makefile`** Okay, so I need to understand what's going on in the `fs/afs/Makefile` file, specifically after line 40. I'm going to jump in there and get a clear picture of that section. It's probably related to a particular build target, dependency declaration, or perhaps some configuration logic. I'm expecting to find some crucial information about the compilation process, linker flags, or maybe even conditional inclusion of source files. I'll be looking for any hints about what exactly the kernel is doing with AFS at that point, like where it is compiling it in or perhaps which part of AFS is being built. Let's see what we've got! |
| 16/2 | 2026/09/07 14:49 | tool | read-file |
0mArgs:{
"File": "fs/afs/Makefile",
"FirstLine": 41,
"LineCount": 20
}Results: {
"Contents": " 41:\t\twrite.o \\\n 42:\t\txattr.o \\\n 43:\t\tyfsclient.o\n 44:\t\n 45:\tkafs-$(CONFIG_PROC_FS) += proc.o\n 46:\tobj-$(CONFIG_AFS_FS) := kafs.o\n"
} |
| 17/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 21109 output: 23 thoughts: 39 Thoughts: Okay, let's dive into this code. I need to understand the relationship between `crypto_krb5_how_much_buffer` and `crypto_krb5_find_enctype`. They're clearly related, and I want to get a solid grasp of how they function. My initial question is: **Where are these two functions defined, and which configuration options or parameters ultimately control their behavior or inclusion?** I need to know the specific source files and any relevant `#ifdef` blocks or conditional compilation flags that determine whether these functions are built into the final executable. This is key to understanding the overall cryptographic configuration and how the system handles different encryption types in Kerberos. It's time to trace the definitions and figure out the dependencies, so I can form a mental map of how these pieces fit into the broader security landscape. |
| 18/2 | 2026/09/07 14:49 | tool | grepper |
0mArgs:{
"Expression": "crypto_krb5_find_enctype"
}Results: {
"Output": "Documentation/crypto/krb5.rst=102=The encoding type is looked up by number using the following function::\nDocumentation/crypto/krb5.rst-103-\nDocumentation/crypto/krb5.rst:104:\tconst struct krb5_enctype *crypto_krb5_find_enctype(u32 enctype);\nDocumentation/crypto/krb5.rst-105-\n--\ncrypto/krb5/krb5_api.c=19=static const struct krb5_enctype *const krb5_supported_enctypes[] = {\n--\ncrypto/krb5/krb5_api.c-28-/**\ncrypto/krb5/krb5_api.c:29: * crypto_krb5_find_enctype - Find the handler for a Kerberos5 encryption type\ncrypto/krb5/krb5_api.c-30- * @enctype: The standard Kerberos encryption type number\n--\ncrypto/krb5/krb5_api.c-34- */\ncrypto/krb5/krb5_api.c:35:const struct krb5_enctype *crypto_krb5_find_enctype(u32 enctype)\ncrypto/krb5/krb5_api.c-36-{\n--\ncrypto/krb5/krb5_api.c-47-}\ncrypto/krb5/krb5_api.c:48:EXPORT_SYMBOL(crypto_krb5_find_enctype);\ncrypto/krb5/krb5_api.c-49-\n--\ncrypto/krb5/selftest.c=118=static int krb5_test_one_prf(const struct krb5_prf_test *test)\ncrypto/krb5/selftest.c-119-{\ncrypto/krb5/selftest.c:120:\tconst struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test-\u003eetype);\ncrypto/krb5/selftest.c-121-\tstruct krb5_buffer key = {}, octet = {}, result = {}, prf = {};\n--\ncrypto/krb5/selftest.c=210=static int krb5_test_one_key(const struct krb5_key_test *test)\ncrypto/krb5/selftest.c-211-{\ncrypto/krb5/selftest.c:212:\tconst struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test-\u003eetype);\ncrypto/krb5/selftest.c-213-\tstruct krb5_buffer base_key = {};\n--\ncrypto/krb5/selftest.c=241=static int krb5_test_one_enc(const struct krb5_enc_test *test, void *buf)\ncrypto/krb5/selftest.c-242-{\ncrypto/krb5/selftest.c:243:\tconst struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test-\u003eetype);\ncrypto/krb5/selftest.c-244-\tstruct crypto_aead *ci = NULL;\n--\ncrypto/krb5/selftest.c=380=static int krb5_test_one_mic(const struct krb5_mic_test *test, void *buf)\ncrypto/krb5/selftest.c-381-{\ncrypto/krb5/selftest.c:382:\tconst struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test-\u003eetype);\ncrypto/krb5/selftest.c-383-\tstruct crypto_shash *ci = NULL;\n--\nfs/afs/cm_security.c=121=int afs_create_token_key(struct afs_net *net, struct socket *socket)\n--\nfs/afs/cm_security.c-142-\tret = -ENOPKG;\nfs/afs/cm_security.c:143:\tkrb5 = crypto_krb5_find_enctype(KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96);\nfs/afs/cm_security.c-144-\tif (!krb5)\n--\nfs/afs/cm_security.c=180=static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n--\nfs/afs/cm_security.c-205-\nfs/afs/cm_security.c:206:\tconn_krb5 = crypto_krb5_find_enctype(enctype);\nfs/afs/cm_security.c-207-\tif (!conn_krb5)\n--\ninclude/crypto/krb5.h=87=struct krb5_enctype {\n--\ninclude/crypto/krb5.h-116- */\ninclude/crypto/krb5.h:117:const struct krb5_enctype *crypto_krb5_find_enctype(u32 enctype);\ninclude/crypto/krb5.h-118-size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,\n--\nnet/ceph/crypto.c=41=static int set_krb5_tfms(struct ceph_crypto_key *key, const u32 *key_usages,\n--\nnet/ceph/crypto.c-51-\nnet/ceph/crypto.c:52:\tkey-\u003ekrb5_type = crypto_krb5_find_enctype(\nnet/ceph/crypto.c-53-\t\t\t KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192);\n--\nnet/rxrpc/key.c=165=static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\n--\nnet/rxrpc/key.c-232-\nnet/rxrpc/key.c:233:\tif (!crypto_krb5_find_enctype(token-\u003erxgk-\u003eenctype)) {\nnet/rxrpc/key.c-234-\t\tret = -ENOPKG;\n--\nnet/rxrpc/rxgk.c=20=static int rxgk_preparse_server_key(struct key_preparsed_payload *prep)\n--\nnet/rxrpc/rxgk.c-35-\nnet/rxrpc/rxgk.c:36:\tkrb5 = crypto_krb5_find_enctype(enctype);\nnet/rxrpc/rxgk.c-37-\tif (!krb5)\n--\nnet/rxrpc/rxgk_kdf.c=205=struct rxgk_context *rxgk_generate_transport_key(struct rxrpc_connection *conn,\n--\nnet/rxrpc/rxgk_kdf.c-222-\nnet/rxrpc/rxgk_kdf.c:223:\tgk-\u003ekrb5 = crypto_krb5_find_enctype(key-\u003eenctype);\nnet/rxrpc/rxgk_kdf.c-224-\tif (!gk-\u003ekrb5)\n--\nnet/rxrpc/rxgk_kdf.c=268=int rxgk_set_up_token_cipher(const struct krb5_buffer *server_key,\n--\nnet/rxrpc/rxgk_kdf.c-276-\nnet/rxrpc/rxgk_kdf.c:277:\tkrb5 = crypto_krb5_find_enctype(enctype);\nnet/rxrpc/rxgk_kdf.c-278-\tif (!krb5)\n--\nnet/rxrpc/rxperf.c=589=static int rxperf_add_yfs_rxgk_key(struct key *keyring, u32 enctype)\nnet/rxrpc/rxperf.c-590-{\nnet/rxrpc/rxperf.c:591:\tconst struct krb5_enctype *krb5 = crypto_krb5_find_enctype(enctype);\nnet/rxrpc/rxperf.c-592-\tkey_ref_t kref;\n--\nnet/sunrpc/auth_gss/gss_krb5_mech.c=46=static void gss_krb5_prepare_enctype_priority_list(void)\n--\nnet/sunrpc/auth_gss/gss_krb5_mech.c-55-\tfor (total = 0, i = 0; i \u003c ARRAY_SIZE(gss_krb5_enctypes); i++) {\nnet/sunrpc/auth_gss/gss_krb5_mech.c:56:\t\tif (!crypto_krb5_find_enctype(gss_krb5_enctypes[i]))\nnet/sunrpc/auth_gss/gss_krb5_mech.c-57-\t\t\tcontinue;\n--\nnet/sunrpc/auth_gss/gss_krb5_mech.c=122=gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,\n--\nnet/sunrpc/auth_gss/gss_krb5_mech.c-146-\t\tgoto out_err;\nnet/sunrpc/auth_gss/gss_krb5_mech.c:147:\tctx-\u003ekrb5e = crypto_krb5_find_enctype(ctx-\u003eenctype);\nnet/sunrpc/auth_gss/gss_krb5_mech.c-148-\tif (!ctx-\u003ekrb5e) {\n"
} |
| 19/2 | 2026/09/07 14:49 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 23690 output: 40 thoughts: 823 Thoughts: **Analyzing the Kernel Configuration and Function Scope** Okay, let's break this down. First, I'm looking at these configuration symbols: `CONFIG_AF_RXRPC`, `CONFIG_AFS_FS`, `CONFIG_RXGK`, and `CONFIG_RXPERF`. The immediate task is to understand their dependencies and relationships, particularly concerning `CRYPTO_KRB5`. It seems both `RXGK` and `AFS_FS` depend on and select `CRYPTO_KRB5`, which is something to keep in mind. Now, focusing on the core dependencies of `AF_RXRPC` and `AFS_FS`, I see that `AF_RXRPC` requires `INET`. `AFS_FS` is dependent on `INET` and also selects `AF_RXRPC`, `DNS_RESOLVER`, `NETFS_SUPPORT`, and, importantly, `CRYPTO_KRB5`. This is useful context. Next, I need to see *how* these configurations manifest in the codebase. I'm going through the list of modified functions, trying to identify their roles: 1. `fs/afs/cm_security.c`: `afs_create_yfs_cm_token` - Security, likely AFS-specific. 2. `fs/afs/internal.h`: `afs_make_op_call` - AFS, internal function call. 3. `fs/afs/rxrpc.c`: `afs_make_call`, `afs_send_empty_reply`, `afs_send_simple_reply` - RXRPC/AFS interaction. 4. `net/rxrpc/call_state.c`: `rxrpc_notify_socket`, `rxrpc_set_call_completion` - RXRPC call management. 5. `net/rxrpc/conn_object.c`: `rxrpc_poke_conn` - RXRPC connection maintenance. 6. `net/rxrpc/key.c`: `rxrpc_preparse_xdr_yfs_rxgk` - RXRPC/YFS/RxGK key parsing. 7. `net/rxrpc/recvmsg.c`: `rxrpc_requeue_call`, `rxrpc_recvmsg` - RXRPC message handling. 8. `net/rxrpc/rxgk.c`: `rxgk_init_connection_security` - RXGK security initialization. 9. `net/rxrpc/rxperf.c`: `rxperf_process_call` - RXPERF performance monitoring. 10. `net/rxrpc/sendmsg.c`: `rxrpc_send_data`, `rxrpc_do_sendmsg`, `rxrpc_kernel_send_data` - RXRPC message sending. Now, I'm checking the most useful symbols, the ones I call "good FocusSymbols". I've compiled a list of symbols based on the functions that were changed and marked them for closer inspection: - `rxrpc_send_data` - `rxrpc_do_sendmsg` - `rxrpc_kernel_send_data` - `rxrpc_recvmsg` - `rxrpc_notify_socket` - `rxrpc_poke_conn` - `rxrpc_preparse_xdr_yfs_rxgk` - `rxgk_init_connection_security` - `afs_make_call` - `afs_send_simple_reply` - `afs_send_empty_reply` - `afs_create_yfs_cm_token` - `rxperf_process_call` The crucial test now is ubiquity. Are any of these functions *everywhere* in the kernel, or are they specific to a particular subsystem? I see that all of them are related to RxRPC, AFS, RxGK, or RxPerf. This means they are localized. To be thorough, I have to ensure all required configs are present: `AF_RXRPC`, `AFS_FS`, `RXGK`, and `RXPERF` are essential, given what I've found. Finally, I'm double-checking the code to see what guards `rxrpc_preparse_xdr_yfs_rxgk`. It seems, from looking at `net/rxrpc/key.c`, that `#ifdef CONFIG_RXGK` may be present, or it may always be compiled in. It depends on how it is guarded. |
| 20/2 | 2026/09/07 14:50 | tool | grepper |
0mArgs:{
"Expression": "rxrpc_preparse_xdr_yfs_rxgk",
"PathPrefix": "net/rxrpc/"
}Results: {
"Output": "net/rxrpc/key.c=137=static time64_t rxrpc_s64_to_time64(s64 time_in_100ns)\n--\nnet/rxrpc/key.c-164- */\nnet/rxrpc/key.c:165:static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\nnet/rxrpc/key.c-166-\t\t\t\t size_t datalen,\n--\nnet/rxrpc/key.c=300=static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)\n--\nnet/rxrpc/key.c-395-\t\tcase RXRPC_SECURITY_YFS_RXGK:\nnet/rxrpc/key.c:396:\t\t\tret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);\nnet/rxrpc/key.c-397-\t\t\tbreak;\n"
} |
| 21/2 | 2026/09/07 14:50 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 25800 output: 263 thoughts: 438 Thoughts: **My Assessment: WorthFuzzing=true** Okay, let's break this down. From looking at the build configurations, I see that `key.c`, `rxgk.c`, `rxperf.c`, and the entire `afs/` directory are compiled under specific conditions: `CONFIG_AF_RXRPC`, `CONFIG_RXGK`, `CONFIG_RXPERF`, and `CONFIG_AFS_FS`, respectively. Naturally, I want to verify which configs are at play here. It looks like we're dealing with `AF_RXRPC`, `AFS_FS`, `RXGK`, and `RXPERF`. The ubiquitous `INET` dependency is implicitly there, as `AF_RXRPC` and `AFS_FS` rely on it. A quick check reveals that `RXGK` is nested under `AF_RXRPC`, and `RXPERF` has its own configuration entry in the `net/rxrpc/Kconfig` file. Now, the crucial question: should `WorthFuzzing` be set to true? Absolutely, yes. The patch series dives deep into core RxRPC send/receive/completion logic, which includes RxGK security context handling, connection poking, key parsing for RxGK, and AFS client send/reply paths. Here's the rationale: the modifications impact key data transmission functions like `rxrpc_send_data`, notification routines like `rxrpc_notify_socket` and `rxrpc_requeue_call`, the parsing of keys within `rxrpc_preparse_xdr_yfs_rxgk`, connection management through `rxrpc_poke_conn`, and, crucially, AFS client calls via `afs_make_call` and `afs_send_simple_reply`. The key here is that all these modified paths are directly exposed and easily reachable via standard methods. We can get to them through AF_RXRPC socket operations, the `add_key` syscall, and standard AFS filesystem interactions within a typical virtualized environment. This level of user-space accessibility makes this code an excellent target for fuzzing. Thus, I'll set `WorthFuzzing=true` and invoke the `set-results` tool accordingly. |
| 22/2 | 2026/09/07 14:50 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"AF_RXRPC",
"AFS_FS",
"RXGK",
"RXPERF"
],
"FocusSymbols": [
"rxrpc_send_data",
"rxrpc_do_sendmsg",
"rxrpc_kernel_send_data",
"rxrpc_recvmsg",
"rxrpc_notify_socket",
"rxrpc_poke_conn",
"rxrpc_preparse_xdr_yfs_rxgk",
"rxgk_init_connection_security",
"afs_make_call",
"afs_send_simple_reply",
"afs_send_empty_reply",
"afs_create_yfs_cm_token",
"rxperf_process_call"
],
"Reasoning": "The patch modifies RxRPC socket data sending and completion notification mechanisms, connection reference counting, key payload parsing, and in-kernel AFS/rxperf send paths. These changes involve core networking and filesystem state machines and error-handling paths that are fully reachable via AF_RXRPC sockets, keys syscalls, and AFS operations in standard virtualized environments.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"AF_RXRPC",
"AFS_FS",
"RXGK",
"RXPERF"
],
"FocusSymbols": [
"rxrpc_send_data",
"rxrpc_do_sendmsg",
"rxrpc_kernel_send_data",
"rxrpc_recvmsg",
"rxrpc_notify_socket",
"rxrpc_poke_conn",
"rxrpc_preparse_xdr_yfs_rxgk",
"rxgk_init_connection_security",
"afs_make_call",
"afs_send_simple_reply",
"afs_send_empty_reply",
"afs_create_yfs_cm_token",
"rxperf_process_call"
],
"Reasoning": "The patch modifies RxRPC socket data sending and completion notification mechanisms, connection reference counting, key payload parsing, and in-kernel AFS/rxperf send paths. These changes involve core networking and filesystem state machines and error-handling paths that are fully reachable via AF_RXRPC sockets, keys syscalls, and AFS operations in standard virtualized environments.",
"WorthFuzzing": true
} |
| 23/1 | 2026/09/07 14:50 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 24/2 | 2026/09/07 14:50 | agent | kmsan-evaluator |
0mModel:core Args: null Results: {
"KMSANReasoning": "The patch series modifies the AF_RXRPC and AFS networking code to support short writes in rxrpc_kernel_send_data, loop until full message consumption in AFS/rxperf callers, simplify locking around rxrpc_send_data, fix the toksize calculation for YFS CM tokens, add encryption type validation for YFS keys, and clean up socket notification and connection refcounting.\n\nNone of these changes expose uninitialized memory risks or kernel-to-user info leaks:\n- The token buffer in `afs_create_yfs_cm_token` is allocated with `kzalloc`, zeroing all bytes; the fix merely accounts for the 4-byte `level` field in `toksize`.\n- In `rxrpc_send_data`, data transfer continues to use `copy_from_iter_full` with bounded copy sizes (`min3`), and error-rewind logic updates byte counters appropriately.\n- Local variables across modified functions (`ret`, `n`, `rewind_by`, etc.) are explicitly initialized or assigned before use.\n- No kernel structures copied to user space (via `copy_to_user`, ioctl, netlink, etc.) or uninitialized padding/struct fields are introduced or altered.\n\nAny concurrency, refcounting, or bounds issues that might arise are fully detectable by standard debug builds (KASAN, LOCKDEP). Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 3d3aff233769081693eda889b58aa3203a62892e
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Sep 7 14:49:22 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index 8926dab8e2e60..7df6aff7644c0 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -879,14 +879,21 @@ The kernel interface functions are as follows:
exclusively to in-kernel virtual addresses. msg.msg_flags may be given
MSG_MORE if there will be subsequent data sends for this call.
- The msg must not specify a destination address, control data or any flags
- other than MSG_MORE. len is the total amount of data to transmit.
+ msg must not specify a destination address, control data or any flags
+ other than MSG_MORE. len is the amount of data to add to the
+ transmission. The last-packet flag will only be set on the outgoing
+ packet if MSG_MORE is not set and len amount of bytes are buffered.
notify_end_rx can be NULL or it can be used to specify a function to be
called when the call changes state to end the Tx phase. This function is
called with a spinlock held to prevent the last DATA packet from being
transmitted until the function returns.
+ The function returns the amount of data buffered or an error. It will
+ return zero only if len is 0 or if msg->msg_iter is empty. It may also
+ make a short write, buffering less than the amount of data provided or the
+ len specified, in which case it should be called again.
+
(#) Receive data from a call::
int rxrpc_kernel_recv_data(struct socket *sock,
diff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c
index 103168c70dd4d..5eeeef761cf31 100644
--- a/fs/afs/cm_security.c
+++ b/fs/afs/cm_security.c
@@ -235,7 +235,7 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,
* struct RXGK_AuthName identities<>;
* };
*/
- toksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
+ toksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
offset = 0;
encsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, &offset);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 290873bac89b3..65a0866cd8b85 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1416,22 +1416,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 = afs_get_call(call, afs_call_trace_get);
- 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);
- afs_put_call(call);
-}
-
static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
{
call->iov_len = size;
@@ -1763,6 +1747,23 @@ 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 = afs_get_call(call, afs_call_trace_get);
+ 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);
+ afs_put_call(call);
+}
+
/*
* 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 d82916657a3dd..1f5b6aa689433 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -412,26 +412,32 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
msg.msg_controllen = 0;
msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
- ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
- &msg, call->request_size,
- afs_notify_end_request_tx);
- if (ret < 0)
- goto error_do_abort;
+ do {
+ ret = rxrpc_kernel_send_data(call->net->socket, rxcall, &msg,
+ msg_data_left(&msg),
+ afs_notify_end_request_tx);
+ if (ret < 0)
+ goto error_do_abort;
+ } while (msg_data_left(&msg) > 0);
if (call->write_iter) {
msg.msg_iter = *call->write_iter;
msg.msg_flags &= ~MSG_MORE;
trace_afs_send_data(call, &msg);
- ret = rxrpc_kernel_send_data(call->net->socket,
- call->rxcall, &msg,
- iov_iter_count(&msg.msg_iter),
- afs_notify_end_request_tx);
+ do {
+ ret = rxrpc_kernel_send_data(call->net->socket,
+ call->rxcall, &msg,
+ msg_data_left(&msg),
+ afs_notify_end_request_tx);
+ if (ret < 0) {
+ trace_afs_sent_data(call, &msg, ret);
+ goto error_do_abort;
+ }
+ } while (msg_data_left(&msg) > 0);
*call->write_iter = msg.msg_iter;
- trace_afs_sent_data(call, &msg, ret);
- if (ret < 0)
- goto error_do_abort;
+ trace_afs_sent_data(call, &msg, 0);
}
/* Note that at this point, we may have received the reply or an abort
@@ -443,10 +449,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
return;
error_do_abort:
- if (ret != -ECONNABORTED)
- rxrpc_kernel_abort_call(call->net->socket, rxcall,
- RX_USER_ABORT, ret,
- afs_abort_send_data_error);
+ rxrpc_kernel_abort_call(call->net->socket, rxcall,
+ RX_USER_ABORT, ret, afs_abort_send_data_error);
if (call->async) {
afs_see_call(call, afs_call_trace_async_abort);
return;
@@ -859,6 +863,7 @@ void afs_send_empty_reply(struct afs_call *call)
{
struct afs_net *net = call->net;
struct msghdr msg;
+ int ret;
_enter("");
@@ -871,22 +876,13 @@ void afs_send_empty_reply(struct afs_call *call)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
- afs_notify_end_reply_tx)) {
- case 0:
- _leave(" [replied]");
+ ret = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
+ afs_notify_end_reply_tx);
+ if (ret >= 0) /* Shouldn't buffer more than 0 bytes. */
return;
- case -ENOMEM:
- _debug("oom");
- rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
- fallthrough;
- default:
- _leave(" [error]");
- return;
- }
+ rxrpc_kernel_abort_call(net->socket, call->rxcall,
+ RXGEN_SS_MARSHAL, ret, afs_abort_send_error);
}
/*
@@ -912,20 +908,21 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
- afs_notify_end_reply_tx);
+ do {
+ n = rxrpc_kernel_send_data(net->socket, call->rxcall,
+ &msg, msg_data_left(&msg),
+ afs_notify_end_reply_tx);
+ } while (n >= 0 && msg_data_left(&msg) > 0);
+
if (n >= 0) {
/* Success */
_leave(" [replied]");
return;
}
- if (n == -ENOMEM) {
- _debug("oom");
- rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
- }
+
+ rxrpc_kernel_abort_call(net->socket, call->rxcall,
+ RXGEN_SS_MARSHAL, n, afs_abort_send_error);
_leave(" [error]");
}
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 1b3c48b5591df..04b0bb682b810 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/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 704a10de66700..52f8718cf7250 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -20,16 +20,16 @@
/* AFS errors */ \
EM(afs_abort_general_error, "afs-error") \
EM(afs_abort_interrupted, "afs-intr") \
- EM(afs_abort_oom, "afs-oom") \
EM(afs_abort_op_not_supported, "afs-op-notsupp") \
EM(afs_abort_probeuuid_negative, "afs-probeuuid-neg") \
EM(afs_abort_send_data_error, "afs-send-data") \
+ EM(afs_abort_send_error, "afs-send-error") \
EM(afs_abort_unmarshal_error, "afs-unmarshal") \
EM(afs_abort_unsupported_sec_class, "afs-unsup-sec-class") \
/* rxperf errors */ \
EM(rxperf_abort_general_error, "rxperf-error") \
- EM(rxperf_abort_oom, "rxperf-oom") \
EM(rxperf_abort_op_not_supported, "rxperf-op-notsupp") \
+ EM(rxperf_abort_send_error, "rxperf-send-error") \
EM(rxperf_abort_unmarshal_error, "rxperf-unmarshal") \
/* RxKAD security errors */ \
EM(rxkad_abort_1_short_check, "rxkad1-short-check") \
@@ -148,6 +148,7 @@
EM(rxrpc_eproto_wrong_security, "wrong-sec") \
EM(rxrpc_recvmsg_excess_data, "recvmsg-excess") \
EM(rxrpc_recvmsg_short_data, "recvmsg-short") \
+ EM(rxrpc_sendmsg_tx_error, "tx-error") \
E_(rxrpc_sendmsg_late_send, "sendmsg-late")
#define rxrpc_call_poke_traces \
@@ -342,6 +343,7 @@
EM(rxrpc_call_see_distribute_error, "SEE dist-err") \
EM(rxrpc_call_see_input, "SEE input ") \
EM(rxrpc_call_see_notify_released, "SEE nfy-rlsd") \
+ EM(rxrpc_call_see_notify_skipped, "SEE nfy-skip") \
EM(rxrpc_call_see_recvmsg, "SEE recvmsg ") \
EM(rxrpc_call_see_recvmsg_requeue, "SEE recv-rqu") \
EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 865f05fe37ab9..cb36a709f540e 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -642,6 +642,7 @@ enum rxrpc_call_flag {
RXRPC_CALL_TX_LAST, /* Last packet in Tx buffer (at rxtx_top) */
RXRPC_CALL_TX_ALL_ACKED, /* Last packet has been hard-acked */
RXRPC_CALL_TX_NO_MORE, /* No more data to transmit (MSG_MORE deasserted) */
+ RXRPC_CALL_TX_ERROR, /* Terminal error; call needs abort */
RXRPC_CALL_SEND_PING, /* A ping will need to be sent */
RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */
RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */
@@ -1109,6 +1110,7 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
/*
* call_state.c
*/
+void rxrpc_notify_socket(struct rxrpc_call *call);
bool rxrpc_set_call_completion(struct rxrpc_call *call,
enum rxrpc_call_completion compl,
u32 abort_code,
@@ -1441,7 +1443,6 @@ extern const struct seq_operations rxrpc_local_seq_ops;
/*
* recvmsg.c
*/
-void rxrpc_notify_socket(struct rxrpc_call *);
int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
/*
diff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c
index 6afb54373ebbf..364810c652766 100644
--- a/net/rxrpc/call_state.c
+++ b/net/rxrpc/call_state.c
@@ -7,6 +7,60 @@
#include "ar-internal.h"
+/*
+ * Post a call for attention by the socket or kernel service.
+ */
+static void __rxrpc_notify_socket(struct rxrpc_call *call)
+{
+ struct rxrpc_sock *rx;
+ struct sock *sk;
+ unsigned long flags;
+
+ if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
+ rxrpc_see_call(call, rxrpc_call_see_notify_released);
+ return;
+ }
+
+ rcu_read_lock();
+
+ rx = rcu_dereference(call->socket);
+ sk = &rx->sk;
+ if (rx && sk->sk_state < RXRPC_CLOSE) {
+ if (call->notify_rx) {
+ spin_lock_irqsave(&call->notify_lock, flags);
+ call->notify_rx(sk, call, call->user_call_ID);
+ spin_unlock_irqrestore(&call->notify_lock, flags);
+ } else {
+ spin_lock_irqsave(&rx->recvmsg_lock, flags);
+ if (list_empty(&call->recvmsg_link)) {
+ rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+ list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+ }
+ spin_unlock_irqrestore(&rx->recvmsg_lock, flags);
+
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ _debug("call %ps", sk->sk_data_ready);
+ sk->sk_data_ready(sk);
+ }
+ }
+ }
+
+ rcu_read_unlock();
+}
+
+/*
+ * Post a call for attention by the socket or kernel service.
+ */
+void rxrpc_notify_socket(struct rxrpc_call *call)
+{
+ if (rxrpc_call_is_complete(call)) {
+ rxrpc_see_call(call, rxrpc_call_see_notify_skipped);
+ return;
+ }
+
+ __rxrpc_notify_socket(call);
+}
+
/*
* Transition a call to the complete state.
*/
@@ -25,7 +79,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,
rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
trace_rxrpc_call_complete(call);
wake_up(&call->waitq);
- rxrpc_notify_socket(call);
+ __rxrpc_notify_socket(call);
return true;
}
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0ece717db0f85..1be50e0c9cee5 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -34,7 +34,10 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
spin_lock_irq(&local->lock);
busy = !list_empty(&conn->attend_link);
if (!busy) {
- rxrpc_get_connection(conn, why);
+ if (!rxrpc_get_connection_maybe(conn, why)) {
+ spin_unlock_irq(&local->lock);
+ return;
+ }
list_add_tail(&conn->attend_link, &local->conn_attend_q);
}
spin_unlock_irq(&local->lock);
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index a0aa78d892897..30d6db052c216 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -172,6 +172,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
const __be32 *ticket, *key;
s64 tmp;
size_t raw_keylen, raw_tktlen, keylen, tktlen;
+ int ret = -EKEYREJECTED;
_enter(",{%x,%x,%x,%x},%x",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -229,6 +230,11 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
token->rxgk->key.data = token->rxgk->_key;
token->rxgk->ticket.len = raw_tktlen;
+ if (!crypto_krb5_find_enctype(token->rxgk->enctype)) {
+ ret = -ENOPKG;
+ goto reject_token;
+ }
+
if (token->rxgk->endtime != 0) {
expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
if (expiry < 0)
@@ -280,7 +286,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
kfree(token->rxgk);
kfree(token);
reject:
- return -EKEYREJECTED;
+ return ret;
expired:
kfree(token->rxgk);
kfree(token);
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index efcba4b2e74f0..28b2148b56936 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -17,13 +17,12 @@
#include "ar-internal.h"
/*
- * Post a call for attention by the socket or kernel service. Further
- * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ * Requeue a call for recvmsg() to pick up.
*/
-void rxrpc_notify_socket(struct rxrpc_call *call)
+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)
{
- struct rxrpc_sock *rx;
- struct sock *sk;
+ struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+ struct sock *sk = &rx->sk;
_enter("%d", call->debug_id);
@@ -32,31 +31,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
return;
}
- rcu_read_lock();
-
- rx = rcu_dereference(call->socket);
- sk = &rx->sk;
- if (rx && sk->sk_state < RXRPC_CLOSE) {
- if (call->notify_rx) {
- spin_lock_irq(&call->notify_lock);
- call->notify_rx(sk, call, call->user_call_ID);
- spin_unlock_irq(&call->notify_lock);
- } else {
- spin_lock_irq(&rx->recvmsg_lock);
- if (list_empty(&call->recvmsg_link)) {
- rxrpc_get_call(call, rxrpc_call_get_notify_socket);
- list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
- }
- spin_unlock_irq(&rx->recvmsg_lock);
+ spin_lock_irq(&rx->recvmsg_lock);
+ if (list_empty(&call->recvmsg_link)) {
+ rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+ list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+ }
+ spin_unlock_irq(&rx->recvmsg_lock);
- if (!sock_flag(sk, SOCK_DEAD)) {
- _debug("call %ps", sk->sk_data_ready);
- sk->sk_data_ready(sk);
- }
- }
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ _debug("call %ps", sk->sk_data_ready);
+ sk->sk_data_ready(sk);
}
- rcu_read_unlock();
_leave("");
}
@@ -561,7 +547,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (!(flags & MSG_PEEK) &&
!skb_queue_empty(&call->recvmsg_queue))
- rxrpc_notify_socket(call);
+ rxrpc_requeue_call(sock, call);
goto not_yet_complete;
call_failed:
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 77a67ace1d248..b49221f57f677 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -251,8 +251,10 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
GFP_NOFS);
if (IS_ERR(gk))
return PTR_ERR(gk);
+ write_lock(&conn->security_use_lock);
conn->rxgk.enctype = gk->krb5->etype;
conn->rxgk.keys[gk->key_number & 3] = gk;
+ write_unlock(&conn->security_use_lock);
switch (conn->security_level) {
case RXRPC_SECURITY_PLAIN:
diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
index b8df6d22314d6..ebd54222c64ef 100644
--- a/net/rxrpc/rxperf.c
+++ b/net/rxrpc/rxperf.c
@@ -538,15 +538,18 @@ static int rxperf_process_call(struct rxperf_call *call)
iov[0].iov_len = len;
iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
msg.msg_flags = 0;
- n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg, len,
- rxperf_notify_end_reply_tx);
+ do {
+ n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall,
+ &msg, msg_data_left(&msg),
+ rxperf_notify_end_reply_tx);
+ } while (n >= 0 && msg_data_left(&msg) > 0);
+
if (n >= 0)
return 0; /* Success */
- if (n == -ENOMEM)
- rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- rxperf_abort_oom);
+ rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
+ RXGEN_SS_MARSHAL, n,
+ rxperf_abort_send_error);
return n;
}
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index ed2c9a51005ad..8bb327dc2833e 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -320,8 +320,8 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)
static int rxrpc_send_data(struct rxrpc_sock *rx,
struct rxrpc_call *call,
struct msghdr *msg, size_t len,
- rxrpc_notify_end_tx_t notify_end_tx,
- bool *_dropped_lock)
+ rxrpc_notify_end_tx_t notify_end_tx)
+ __releases(&call->user_mutex)
{
struct rxrpc_txbuf *txb;
struct sock *sk = &rx->sk;
@@ -330,29 +330,37 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
bool more = msg->msg_flags & MSG_MORE;
int ret, copied = 0;
- if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
- trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
- call->cid, call->call_id, call->rx_consumed,
- 0, -EPROTO);
- return -EPROTO;
- }
-
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
ret = rxrpc_wait_to_be_connected(call, &timeo);
if (ret < 0)
- return ret;
+ goto out_unlock;
if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
ret = rxrpc_init_client_conn_security(call->conn);
if (ret < 0)
- return ret;
+ goto out_unlock;
}
/* this should be in poll */
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
reload:
+ if (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags))) {
+ trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
+ call->cid, call->call_id, call->rx_consumed,
+ 0, -EPROTO);
+ ret = -EPROTO;
+ goto maybe_error;
+ }
+ if (unlikely(test_bit(RXRPC_CALL_TX_ERROR, &call->flags))) {
+ trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_tx_error,
+ call->cid, call->call_id, call->rx_consumed,
+ 0, -EIO);
+ ret = -EIO;
+ goto maybe_error;
+ }
+
txb = call->tx_pending;
call->tx_pending = NULL;
if (txb)
@@ -379,9 +387,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = -EMSGSIZE;
if (call->tx_total_len != -1) {
- if (len - copied > call->tx_total_len)
+ if (len > call->tx_total_len)
goto maybe_error;
- if (!more && len - copied != call->tx_total_len)
+ if (!more && len != call->tx_total_len)
goto maybe_error;
}
@@ -405,7 +413,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
* the security header is going to be in the padded
* region (enc blocksize), but the trailer is not.
*/
- remain = more ? INT_MAX : msg_data_left(msg);
+ remain = more ? INT_MAX : len;
txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation);
if (!txb) {
ret = -ENOMEM;
@@ -416,8 +424,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
_debug("append");
/* append next segment of data to the current buffer */
- if (msg_data_left(msg) > 0) {
- size_t copy = umin(txb->space, msg_data_left(msg));
+ if (len > 0) {
+ size_t copy = min3(txb->space, len, msg_data_left(msg));
_debug("add %zu", copy);
if (!copy_from_iter_full(txb->data + txb->offset,
@@ -428,6 +436,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
txb->len += copy;
txb->offset += copy;
copied += copy;
+ len -= copy;
if (call->tx_total_len != -1)
call->tx_total_len -= copy;
}
@@ -439,62 +448,100 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
/* add the packet to the send queue if it's now full */
if (!txb->space ||
- (msg_data_left(msg) == 0 && !more)) {
- if (msg_data_left(msg) == 0 && !more)
- txb->flags |= RXRPC_LAST_PACKET;
-
+ (len == 0 && !more)) {
+ /* Do any required crypto. If this fails, it could
+ * have corrupted the txbuf content with a partial
+ * encrypt. Assume that ENOMEM is retryable, but
+ * everything else is terminal.
+ */
ret = call->security->secure_packet(call, txb);
- if (ret < 0)
- goto out;
+ if (ret < 0) {
+ /* Assume that ENOMEM here means that the
+ * encryption hasn't happened yet. The data is
+ * aligned to avoid the need for slow buffering
+ * in the crypto walk.
+ */
+ if (ret == -ENOMEM)
+ goto maybe_error_rewind;
+ set_bit(RXRPC_CALL_TX_ERROR, &call->flags);
+ goto out_txb;
+ }
+
+ if (len == 0 && !more)
+ txb->flags |= RXRPC_LAST_PACKET;
rxrpc_queue_packet(rx, call, txb, notify_end_tx);
txb = NULL;
}
- } while (msg_data_left(msg) > 0);
+ } while (len > 0 && msg_data_left(msg) > 0);
success:
ret = copied;
- if (rxrpc_call_is_complete(call) &&
- call->error < 0)
- ret = call->error;
-out:
+out_txb:
call->tx_pending = txb;
+out_unlock:
+ mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
call_terminated:
rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
- _leave(" = %d", call->error);
- return call->error;
-
+ call->tx_pending = NULL;
+ ret = call->error;
+ goto out_unlock;
+
+maybe_error_rewind:
+ /* If we got a retryable error after copying all the supplied data into
+ * the last packet, we need to rewind as much as we can so the caller
+ * knows they need to retry the sendmsg.
+ */
+ if (copied && !more && !len) {
+ unsigned int rewind_by = umin(copied, txb->len);
+
+ txb->space += rewind_by;
+ txb->len -= rewind_by;
+ txb->offset -= rewind_by;
+ copied -= rewind_by;
+ if (call->tx_total_len != -1)
+ call->tx_total_len += rewind_by;
+ iov_iter_revert(&msg->msg_iter, rewind_by);
+ }
maybe_error:
- if (copied)
+ if (copied) {
+ if (rxrpc_call_is_complete(call) &&
+ call->error < 0) {
+ ret = call->error;
+ goto out_txb;
+ }
goto success;
- goto out;
+ }
+ goto out_txb;
efault:
ret = -EFAULT;
- goto out;
+ goto out_txb;
wait_for_space:
ret = -EAGAIN;
if (msg->msg_flags & MSG_DONTWAIT)
goto maybe_error;
mutex_unlock(&call->user_mutex);
- *_dropped_lock = true;
+
ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
msg->msg_flags & MSG_WAITALL);
if (ret < 0)
- goto maybe_error;
+ goto out_nolock;
if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
if (mutex_lock_interruptible(&call->user_mutex) < 0) {
ret = sock_intr_errno(timeo);
- goto maybe_error;
+ goto out_nolock;
}
} else {
mutex_lock(&call->user_mutex);
}
- *_dropped_lock = false;
goto reload;
+out_nolock:
+ _leave(" = %d [intr]", ret);
+ return copied ?: ret;
}
/*
@@ -660,7 +707,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
{
struct rxrpc_call *call;
- bool dropped_lock = false;
int ret;
struct rxrpc_send_params p = {
@@ -769,16 +815,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
ret = 0;
break;
case RXRPC_CMD_SEND_DATA:
- ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
- break;
+ ret = rxrpc_send_data(rx, call, msg, len, NULL);
+ goto error_put;
default:
ret = -EINVAL;
break;
}
out_put_unlock:
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
+ mutex_unlock(&call->user_mutex);
error_put:
rxrpc_put_call(call, rxrpc_call_put_sendmsg);
_leave(" = %d", ret);
@@ -800,15 +845,21 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
* Allow a kernel service to send data on a call. The call must be in an state
* appropriate to sending data. No control data should be supplied in @msg,
* nor should an address be supplied. MSG_MORE should be flagged if there's
- * more data to come, otherwise this data will end the transmission phase.
+ * more data to come, otherwise this data will end the transmission phase if
+ * all the data is buffered.
+ *
+ * Note that this function may return a short send, in which case it should be
+ * called again for the remainder of the data or to pick up an error that
+ * caused the short send.
*
- * Return: %0 if successful and a negative error code otherwise.
+ * Return: The number of bytes buffered (could be %0 if @len is 0 or
+ * msg_iter holds 0 bytes) if successful and a negative error code
+ * otherwise.
*/
int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
struct msghdr *msg, size_t len,
rxrpc_notify_end_tx_t notify_end_tx)
{
- bool dropped_lock = false;
int ret;
_enter("{%d},", call->debug_id);
@@ -819,12 +870,10 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
mutex_lock(&call->user_mutex);
ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
- notify_end_tx, &dropped_lock);
+ notify_end_tx);
if (ret == -ESHUTDOWN)
ret = call->error;
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
}
|
| 25/3 | 2026/09/07 14:50 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 13347 output: 37 thoughts: 805 Thoughts: **Analyzing the Patch Series for KMSAN Risks**
Okay, let's dive into this patch series. My initial thought is to break down each change systematically and scrutinize it for potential Kernel Memory Sanitizer (KMSAN) risks. I need to be thorough; sloppy analysis here could lead to hard-to-debug issues.
First, I'll go through the patch file by file, noting the changes. So, it looks like:
1. Documentation got an update, specifically concerning `rxrpc_kernel_send_data`. That's mostly cosmetic, but I'll make a note just in case documentation is critical.
2. `afs_create_yfs_cm_token` in `fs/afs/cm_security.c` has a fixed-size calculation for `toksize`. Okay, that seems straightforward, but I'll need to double-check that this calculation is correct and doesn't introduce any new vulnerabilities related to buffer overflows or underflows. The change to add 4 bytes could be significant.
3. Some refactoring with `afs_make_op_call` and server handling in `fs/afs/internal.h`. Moving that and adding a server use is a definite area to scrutinize for potential races or uninitialized memory issues.
4. There's a loop using `rxrpc_kernel_send_data` in `fs/afs/rxrpc.c`, so it will now keep looping until all data is sent. I will need to ensure the loop conditions and data handling are robust and that there aren't any potential issues with partial writes or uninitialized memory during the iterative process.
5. Added some trace events for AFS and RxRPC, which won't pose KMSAN risks directly. But, any extra trace event should still be checked in context of other changes.
6. Some internal RxRPC functions, like `__rxrpc_notify_socket` and `rxrpc_notify_socket`, are separated. Internal refactoring can be dangerous if not done correctly, so I'll need to examine how these changes impact the calling contexts.
7. A new function `rxrpc_get_connection_maybe` is added; I'll check its usage and initialization.
8. There's a check for `crypto_krb5_find_enctype` in RxRPC key handling. Security-related changes are always worth extra scrutiny.
9. `rxrpc_requeue_call` replaces `rxrpc_notify_socket`. I need to understand why this change was made and if it impacts any data flow or error handling.
10. Locking added in `rxgk.c` – locking is always good but can be problematic. I need to ensure it's correct and that there are no race conditions.
11. RxPerf also loops on data send; same considerations as above.
12. Significant changes in `net/rxrpc/sendmsg.c`:
* Locking handling within `rxrpc_send_data` is cleaned up. I'll need to confirm that the lock/unlock operations are correct and that this doesn't lead to any deadlocks or race conditions.
* Short sends, returning byte count – a change in function semantics, specifically related to the loop I noted before. This is the heart of the changes, and I need to ensure that the byte count is correct and that error handling is sound. `iov_iter_revert` in `maybe_error_rewind` needs a hard look.
* The signature and semantics of `rxrpc_kernel_send_data` have been modified, with a return value change. The callers now loop. This is critical, as this alters data flow, and I'll need to trace its new usage throughout the kernel to check for uninitialized data.
Now, let's switch gears and put on my KMSAN hat. I'll need to answer a series of questions as I scrutinize each file:
1. **Does this patch introduce or modify kernel structures sent to user space?** I need to look for any instances of `copy_to_user`, `put_user`, netlink skb attributes, ioctl output arguments, socket options, or BPF buffers. I'll need to ensure that the data being sent is fully initialized and zeroed out.
2. **Does this patch introduce conditional logic or branching that depends on potentially uninitialized variables?** I need to carefully check any `if` statements or other conditional structures to ensure that the variables used in the conditions are always initialized before they are used.
3. **Does this patch allocate or initialize complex data structures where uninitialized fields could be read later in reachable code paths?** I will be on the lookout for any cases where new structures are allocated
|
| 26/3 | 2026/09/07 14:50 | tool | read-file |
0mArgs:{
"File": "fs/afs/cm_security.c",
"FirstLine": 220,
"LineCount": 50
}Results: {
"Contents": " 220:\t\t *\tafs_int32\tkind;\n 221:\t\t *\topaque\t\tdata\u003cAUTHDATAMAX\u003e;\n 222:\t\t *\topaque\t\tdisplay\u003cAUTHPRINTABLEMAX\u003e;\n 223:\t\t * };\n 224:\t\t */\n 225:\t\tuuidsize = sizeof(server-\u003euuid);\n 226:\t\tauthsize = 4 + xdr_len_object(uuidsize) + xdr_len_object(0);\n 227:\t\n 228:\t\t/* struct RXGK_Token {\n 229:\t\t *\trxgk_key\t\tK0;\n 230:\t\t *\tRXGK_Level\t\tlevel;\n 231:\t\t *\trxgkTime\t\tstarttime;\n 232:\t\t *\tafs_int32\t\tlifetime;\n 233:\t\t *\tafs_int32\t\tbytelife;\n 234:\t\t *\trxgkTime\t\texpirationtime;\n 235:\t\t *\tstruct RXGK_AuthName\tidentities\u003c\u003e;\n 236:\t\t * };\n 237:\t\t */\n 238:\t\ttoksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);\n 239:\t\n 240:\t\toffset = 0;\n 241:\t\tencsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, \u0026offset);\n 242:\t\n 243:\t\t/* struct RXGK_TokenContainer {\n 244:\t\t *\tafs_int32\tkvno;\n 245:\t\t *\tafs_int32\tenctype;\n 246:\t\t *\topaque\t\tencrypted_token\u003c\u003e;\n 247:\t\t * };\n 248:\t\t */\n 249:\t\tcontsize = 4 + 4 + xdr_len_object(encsize);\n 250:\t\n 251:\t\t/* struct YFSAppData {\n 252:\t\t *\topr_uuid\tinitiatorUuid;\n 253:\t\t *\topr_uuid\tacceptorUuid;\n 254:\t\t *\tCapabilities\tcaps;\n 255:\t\t *\tafs_int32\tenctype;\n 256:\t\t *\topaque\t\tcallbackKey\u003c\u003e;\n 257:\t\t *\topaque\t\tcallbackToken\u003c\u003e;\n 258:\t\t * };\n 259:\t\t */\n 260:\t\tadatasize = 16 + 16 +\n 261:\t\t\txdr_len_object(sizeof(caps)) +\n 262:\t\t\t4 +\n 263:\t\t\txdr_len_object(conn_krb5-\u003ekey_len) +\n 264:\t\t\txdr_len_object(contsize);\n 265:\t\n 266:\t\tret = -ENOMEM;\n 267:\t\tappdata = kzalloc(adatasize, GFP_KERNEL);\n 268:\t\tif (!appdata)\n 269:\t\t\tgoto out;\n"
} |
| 27/3 | 2026/09/07 14:50 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 16009 output: 37 thoughts: 187 Thoughts: **Analyzing the Token Creation** Okay, let's break down this `afs_create_yfs_cm_token` function. Looking at the `RXGK_Token` struct definition, I see a few things that immediately jump out. I remember from my prior experience that the struct comment itself is key. Specifically, the struct has `K0`, `level`, `starttime`, `lifetime`, `bytelife`, `expirationtime`, and then `identities`, which is a variable-length array based on `authsize`. I see that there was a previous error in calculating `toksize`. The comment says the issue was that the size calculation was missing 4 bytes for the `RXGK_Level level` field. So, the old `toksize` allocation would have been insufficient. The addition of `+ 4` to the calculation now corrects this by including the size of `RXGK_Level level`, ensuring we allocate enough space for the entire token structure. The token allocation size seems good now. I'll need to check how the `tok` variable, which is the token itself, is allocated and how its fields are populated to make sure everything is being done correctly. |
| 28/3 | 2026/09/07 14:50 | tool | read-file |
0mArgs:{
"File": "fs/afs/cm_security.c",
"FirstLine": 270,
"LineCount": 50
}Results: {
"Contents": " 270:\t\txdr = appdata;\n 271:\t\n 272:\t\tmemcpy(xdr, \u0026net-\u003euuid, 16);\t\t/* appdata.initiatorUuid */\n 273:\t\txdr += 16 / 4;\n 274:\t\tmemcpy(xdr, \u0026server-\u003euuid, 16);\t\t/* appdata.acceptorUuid */\n 275:\t\txdr += 16 / 4;\n 276:\t\t*xdr++ = htonl(ARRAY_SIZE(caps));\t/* appdata.caps.len */\n 277:\t\tmemcpy(xdr, \u0026caps, sizeof(caps));\t/* appdata.caps */\n 278:\t\txdr += ARRAY_SIZE(caps);\n 279:\t\t*xdr++ = htonl(conn_krb5-\u003eetype);\t/* appdata.enctype */\n 280:\t\n 281:\t\t*xdr++ = htonl(conn_krb5-\u003ekey_len);\t/* appdata.callbackKey.len */\n 282:\t\tK0 = xdr;\n 283:\t\tget_random_bytes(K0, conn_krb5-\u003ekey_len); /* appdata.callbackKey.data */\n 284:\t\txdr += xdr_round_up(conn_krb5-\u003ekey_len) / 4;\n 285:\t\n 286:\t\t*xdr++ = htonl(contsize);\t\t/* appdata.callbackToken.len */\n 287:\t\t*xdr++ = htonl(1);\t\t\t/* cont.kvno */\n 288:\t\t*xdr++ = htonl(token_krb5-\u003eetype);\t/* cont.enctype */\n 289:\t\t*xdr++ = htonl(encsize);\t\t/* cont.encrypted_token.len */\n 290:\t\n 291:\t\tencbase = xdr;\n 292:\t\txdr += offset / 4;\n 293:\t\t*xdr++ = htonl(conn_krb5-\u003eetype);\t/* token.K0.enctype */\n 294:\t\t*xdr++ = htonl(conn_krb5-\u003ekey_len);\t/* token.K0.key.len */\n 295:\t\tmemcpy(xdr, K0, conn_krb5-\u003ekey_len);\t/* token.K0.key.data */\n 296:\t\txdr += xdr_round_up(conn_krb5-\u003ekey_len) / 4;\n 297:\t\n 298:\t\t*xdr++ = htonl(RXRPC_SECURITY_ENCRYPT);\t/* token.level */\n 299:\t\t*xdr++ = htonl(0);\t\t\t/* token.starttime */\n 300:\t\t*xdr++ = htonl(0);\t\t\t/* \" */\n 301:\t\t*xdr++ = htonl(0);\t\t\t/* token.lifetime */\n 302:\t\t*xdr++ = htonl(0);\t\t\t/* token.bytelife */\n 303:\t\t*xdr++ = htonl(0);\t\t\t/* token.expirationtime */\n 304:\t\t*xdr++ = htonl(0);\t\t\t/* \" */\n 305:\t\t*xdr++ = htonl(1);\t\t\t/* token.identities.count */\n 306:\t\t*xdr++ = htonl(0);\t\t\t/* token.identities[0].kind */\n 307:\t\t*xdr++ = htonl(uuidsize);\t\t/* token.identities[0].data.len */\n 308:\t\tmemcpy(xdr, \u0026server-\u003euuid, uuidsize);\n 309:\t\txdr += xdr_round_up(uuidsize) / 4;\n 310:\t\t*xdr++ = htonl(0);\t\t\t/* token.identities[0].display.len */\n 311:\t\n 312:\t\txdr = encbase + xdr_round_up(encsize);\n 313:\t\n 314:\t\tif ((unsigned long)xdr - (unsigned long)appdata != adatasize)\n 315:\t\t\tpr_err(\"Appdata size incorrect %lx != %zx\\n\",\n 316:\t\t\t (unsigned long)xdr - (unsigned long)appdata, adatasize);\n 317:\t\n 318:\t\taead = crypto_krb5_prepare_encryption(token_krb5, token_key, RXGK_SERVER_ENC_TOKEN,\n 319:\t\t\t\t\t\t GFP_KERNEL);\n"
} |
| 29/3 | 2026/09/07 14:50 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 17593 output: 37 thoughts: 125 Thoughts: **Analyzing the Buffer Size Calculation Fix** Okay, so the fix is in for a buffer size calculation error related to `toksize`. The memory was initially allocated using `kzalloc`, meaning everything started out zeroed. The bug was in failing to account for the 4-byte `level` field that gets written later, as evidenced by the `htonl(RXRPC_SECURITY_ENCRYPT)` call on line 298. Essentially, we were under-allocating, even though the consequences weren't immediately obvious due to the zero initialization. It looks like it was only fixing a buffer size calculation, not a memory corruption, but it is important to check how the buffer will be used. Now, let's dig into the details. Time to thoroughly analyze `net/rxrpc/sendmsg.c` and related files to understand the full implications and make sure there aren't any further issues lurking. Let's start with `net/rxrpc/sendmsg.c` itself. |
| 30/3 | 2026/09/07 14:50 | tool | read-file |
0mArgs:{
"File": "net/rxrpc/sendmsg.c",
"FirstLine": 380,
"LineCount": 90
}Results: {
"Contents": " 380:\t\t state != RXRPC_CALL_SERVER_SEND_REPLY) {\n 381:\t\t\t/* Request phase complete for this client call */\n 382:\t\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_late_send,\n 383:\t\t\t\t\t call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n 384:\t\t\t\t\t 0, -EPROTO);\n 385:\t\t\tgoto maybe_error;\n 386:\t\t}\n 387:\t\n 388:\t\tret = -EMSGSIZE;\n 389:\t\tif (call-\u003etx_total_len != -1) {\n 390:\t\t\tif (len \u003e call-\u003etx_total_len)\n 391:\t\t\t\tgoto maybe_error;\n 392:\t\t\tif (!more \u0026\u0026 len != call-\u003etx_total_len)\n 393:\t\t\t\tgoto maybe_error;\n 394:\t\t}\n 395:\t\n 396:\t\tdo {\n 397:\t\t\tif (!txb) {\n 398:\t\t\t\tsize_t remain;\n 399:\t\n 400:\t\t\t\t_debug(\"alloc\");\n 401:\t\n 402:\t\t\t\tif (!rxrpc_check_tx_space(call, NULL))\n 403:\t\t\t\t\tgoto wait_for_space;\n 404:\t\n 405:\t\t\t\t/* See if we need to begin/extend the Tx queue. */\n 406:\t\t\t\tif (!call-\u003esend_queue || !((call-\u003esend_top + 1) \u0026 RXRPC_TXQ_MASK)) {\n 407:\t\t\t\t\tret = rxrpc_alloc_txqueue(sk, call);\n 408:\t\t\t\t\tif (ret \u003c 0)\n 409:\t\t\t\t\t\tgoto maybe_error;\n 410:\t\t\t\t}\n 411:\t\n 412:\t\t\t\t/* Work out the maximum size of a packet. Assume that\n 413:\t\t\t\t * the security header is going to be in the padded\n 414:\t\t\t\t * region (enc blocksize), but the trailer is not.\n 415:\t\t\t\t */\n 416:\t\t\t\tremain = more ? INT_MAX : len;\n 417:\t\t\t\ttxb = call-\u003econn-\u003esecurity-\u003ealloc_txbuf(call, remain, sk-\u003esk_allocation);\n 418:\t\t\t\tif (!txb) {\n 419:\t\t\t\t\tret = -ENOMEM;\n 420:\t\t\t\t\tgoto maybe_error;\n 421:\t\t\t\t}\n 422:\t\t\t}\n 423:\t\n 424:\t\t\t_debug(\"append\");\n 425:\t\n 426:\t\t\t/* append next segment of data to the current buffer */\n 427:\t\t\tif (len \u003e 0) {\n 428:\t\t\t\tsize_t copy = min3(txb-\u003espace, len, msg_data_left(msg));\n 429:\t\n 430:\t\t\t\t_debug(\"add %zu\", copy);\n 431:\t\t\t\tif (!copy_from_iter_full(txb-\u003edata + txb-\u003eoffset,\n 432:\t\t\t\t\t\t\t copy, \u0026msg-\u003emsg_iter))\n 433:\t\t\t\t\tgoto efault;\n 434:\t\t\t\t_debug(\"added\");\n 435:\t\t\t\ttxb-\u003espace -= copy;\n 436:\t\t\t\ttxb-\u003elen += copy;\n 437:\t\t\t\ttxb-\u003eoffset += copy;\n 438:\t\t\t\tcopied += copy;\n 439:\t\t\t\tlen -= copy;\n 440:\t\t\t\tif (call-\u003etx_total_len != -1)\n 441:\t\t\t\t\tcall-\u003etx_total_len -= copy;\n 442:\t\t\t}\n 443:\t\n 444:\t\t\t/* check for the far side aborting the call or a network error\n 445:\t\t\t * occurring */\n 446:\t\t\tif (rxrpc_call_is_complete(call))\n 447:\t\t\t\tgoto call_terminated;\n 448:\t\n 449:\t\t\t/* add the packet to the send queue if it's now full */\n 450:\t\t\tif (!txb-\u003espace ||\n 451:\t\t\t (len == 0 \u0026\u0026 !more)) {\n 452:\t\t\t\t/* Do any required crypto. If this fails, it could\n 453:\t\t\t\t * have corrupted the txbuf content with a partial\n 454:\t\t\t\t * encrypt. Assume that ENOMEM is retryable, but\n 455:\t\t\t\t * everything else is terminal.\n 456:\t\t\t\t */\n 457:\t\t\t\tret = call-\u003esecurity-\u003esecure_packet(call, txb);\n 458:\t\t\t\tif (ret \u003c 0) {\n 459:\t\t\t\t\t/* Assume that ENOMEM here means that the\n 460:\t\t\t\t\t * encryption hasn't happened yet. The data is\n 461:\t\t\t\t\t * aligned to avoid the need for slow buffering\n 462:\t\t\t\t\t * in the crypto walk.\n 463:\t\t\t\t\t */\n 464:\t\t\t\t\tif (ret == -ENOMEM)\n 465:\t\t\t\t\t\tgoto maybe_error_rewind;\n 466:\t\t\t\t\tset_bit(RXRPC_CALL_TX_ERROR, \u0026call-\u003eflags);\n 467:\t\t\t\t\tgoto out_txb;\n 468:\t\t\t\t}\n 469:\t\n"
} |
| 31/3 | 2026/09/07 14:50 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 19309 output: 328 thoughts: 1715 Thoughts: **KMSAN Assessment: RxRPC Patch Review** Okay, let's break down this RxRPC patch and determine if it warrants a `NeedsKMSAN=true` flag. My focus is on identifying potential uninitialized memory reads or information leaks, given the critical nature of this area. First, I examined `alloc_txbuf` and `secure_packet` within `rxrpc`. The patch introduces a `copy_from_iter_full` call, copying data into the transmit buffer (`txb`). The crucial thing here is that the `txb->len` is *only* incremented by the copied amount and that the `rxrpc_queue_packet` function accurately reflects the amount copied. Also, `rxrpc_kernel_send_data` now returns the *number of bytes buffered* which indicates success - not zero - so there is no concern there. Next, I looked at how `rxrpc_kernel_send_data` is used in several `fs/afs/rxrpc.c` functions: `afs_make_call`, `afs_send_empty_reply`, `afs_send_simple_reply`, and `rxperf_process_call`. Each uses a `do...while` loop that calls `rxrpc_kernel_send_data` repeatedly until all the message data is sent. The loop conditions (`msg_data_left(&msg) > 0` or `n >= 0 && msg_data_left(&msg) > 0`) appear sound; if a negative return code is returned, the loop is exited. `ret` and `n` are assigned before use and their usage is checked. Now, the real litmus test: the four KMSAN criteria. 1. **Kernel-to-User Space:** I'm meticulously looking for any `copy_to_user`, `put_user`, netlink, ioctl, or BPF changes. The patch has `rxrpc_requeue_call`, `__rxrpc_notify_socket`, `rxrpc_notify_socket` in `recvmsg.c` and `call_state.c` but these appear to be internal notifications, not direct user-facing copies. `rxrpc_preparse_xdr_yfs_rxgk` in `key.c` returns `ret` which is assigned with `-EKEYREJECTED` and the return value is checked. The `toksize` calculation fix in `cm_security.c` is important to confirm there are no buffer overflows or similar bugs. 2. **Conditional Logic/Branching:** I'm inspecting all variables used in conditional statements to ensure they're initialized before use. The code uses `ret` and `n` which are initialized before use in all instances, as well as `rewind_by` which is initialized by `umin(copied, txb->len)`. 3. **Complex Data Structures:** I'm checking for allocation or initialization of data structures where uninitialized fields could be read later. I don't see any obvious examples of this here. 4. **Bounds/Length Checks:** The `sendmsg.c` changes meticulously track `len` and `msg_data_left(msg)`. The code is careful with `min3(txb->space, len, msg_data_left(msg))` and data is copied directly from `msg_iter`. No uninitialized bytes are being accessed or transmitted. I've carefully double-checked *all* the diff hunks. I reviewed the documentation (`Documentation/networking/rxrpc.rst`) and other related changes like fixes to `toksize` calculation (`fs/afs/cm_security.c`), inline function moves (`fs/afs/internal.h`), the loops with `rxrpc_kernel_send_data` in `fs/afs/rxrpc.c`, trace events, declarations and flag enums (`net/rxrpc/ar-internal.h`), socket notification logic cleanup, null/ref checks, `crypto_krb5_find_enctype` validation, helper functions, and locking. Based on this comprehensive review, I'm confident there are *no* direct risks of uninitialized memory reads or kernel information leaks introduced by this patch. Standard kernel protections (KASAN, LOCKDEP, etc.) should catch any other potential issues. Therefore, I'm recommending `NeedsKMSAN=false`. Let's call `set-results` with that, along with this detailed reasoning. |
| 32/3 | 2026/09/07 14:50 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series modifies the AF_RXRPC and AFS networking code to support short writes in rxrpc_kernel_send_data, loop until full message consumption in AFS/rxperf callers, simplify locking around rxrpc_send_data, fix the toksize calculation for YFS CM tokens, add encryption type validation for YFS keys, and clean up socket notification and connection refcounting.\n\nNone of these changes expose uninitialized memory risks or kernel-to-user info leaks:\n- The token buffer in `afs_create_yfs_cm_token` is allocated with `kzalloc`, zeroing all bytes; the fix merely accounts for the 4-byte `level` field in `toksize`.\n- In `rxrpc_send_data`, data transfer continues to use `copy_from_iter_full` with bounded copy sizes (`min3`), and error-rewind logic updates byte counters appropriately.\n- Local variables across modified functions (`ret`, `n`, `rewind_by`, etc.) are explicitly initialized or assigned before use.\n- No kernel structures copied to user space (via `copy_to_user`, ioctl, netlink, etc.) or uninitialized padding/struct fields are introduced or altered.\n\nAny concurrency, refcounting, or bounds issues that might arise are fully detectable by standard debug builds (KASAN, LOCKDEP). Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series modifies the AF_RXRPC and AFS networking code to support short writes in rxrpc_kernel_send_data, loop until full message consumption in AFS/rxperf callers, simplify locking around rxrpc_send_data, fix the toksize calculation for YFS CM tokens, add encryption type validation for YFS keys, and clean up socket notification and connection refcounting.\n\nNone of these changes expose uninitialized memory risks or kernel-to-user info leaks:\n- The token buffer in `afs_create_yfs_cm_token` is allocated with `kzalloc`, zeroing all bytes; the fix merely accounts for the 4-byte `level` field in `toksize`.\n- In `rxrpc_send_data`, data transfer continues to use `copy_from_iter_full` with bounded copy sizes (`min3`), and error-rewind logic updates byte counters appropriately.\n- Local variables across modified functions (`ret`, `n`, `rewind_by`, etc.) are explicitly initialized or assigned before use.\n- No kernel structures copied to user space (via `copy_to_user`, ioctl, netlink, etc.) or uninitialized padding/struct fields are introduced or altered.\n\nAny concurrency, refcounting, or bounds issues that might arise are fully detectable by standard debug builds (KASAN, LOCKDEP). Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|