The Ceph messenger v1 and v2 protocol implementations currently use WARN_ON() to assert that the server's response adheres to the protocol. However, network input from a server can be invalid due to a buggy or malicious server. WARN_ON() must not be used for conditions that can legitimately happen, such as receiving invalid network data. While WARNINGs are not fatal by default, they pollute the kernel log with stack traces and can lead to kernel panics on systems configured with panic_on_warn. When the kernel Ceph client connects to a Ceph server, it initiates a handshake and reads the server's reply directly from the network socket. The reply is then processed in process_connect() (for v1) or other processing functions (for v2). If the server sends an unexpected value, such as an incorrect connect_seq, the client triggers a WARN_ON(), resulting in the following warning: ------------[ cut here ]------------ con->v1.connect_seq != le32_to_cpu(con->v1.in_reply.connect_seq) WARNING: net/ceph/messenger_v1.c:902 at process_connect net/ceph/messenger_v1.c:901 [inline], CPU#1: kworker/1:3/5645 WARNING: net/ceph/messenger_v1.c:902 at ceph_con_v1_try_read+0x3335/0x6eb0 net/ceph/messenger_v1.c:1366, CPU#1: kworker/1:3/5645 RIP: 0010:process_connect net/ceph/messenger_v1.c:901 [inline] RIP: 0010:ceph_con_v1_try_read+0x3335/0x6eb0 net/ceph/messenger_v1.c:1366 Call Trace: ceph_con_workfn+0x208/0x14a0 net/ceph/messenger.c:1577 process_one_work kernel/workqueue.c:3322 [inline] process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405 worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486 kthread+0x388/0x470 kernel/kthread.c:436 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 Fix this by replacing WARN_ON() assertions on network input with graceful error handling. If the server sends unexpected data, log a descriptive error message using pr_err() instead, set the connection error message, and return an error code to abort the connection. This ensures that invalid network input is treated as a protocol violation rather than a kernel bug. The fix is applied to both messenger v1 (process_connect) and v2 (process_hello, process_server_ident, process_session_retry, and process_session_retry_global). Fixes: 31b8006e1d79 ("ceph: messenger library") Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot Reported-by: syzbot+21f8628595b2061c438d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=21f8628595b2061c438d Link: https://syzkaller.appspot.com/ai_job?id=56e865ad-bcea-4dc1-9df8-618a118f27c9 To: "Alex Markuze" To: To: "Ilya Dryomov" To: "Viacheslav Dubeyko" To: "Sage Weil" Cc: --- diff --git a/net/ceph/messenger_v1.c b/net/ceph/messenger_v1.c index c9e002d96..df2248b7b 100644 --- a/net/ceph/messenger_v1.c +++ b/net/ceph/messenger_v1.c @@ -898,8 +898,15 @@ static int process_connect(struct ceph_connection *con) con->v1.peer_global_seq, le32_to_cpu(con->v1.in_reply.connect_seq), con->v1.connect_seq); - WARN_ON(con->v1.connect_seq != - le32_to_cpu(con->v1.in_reply.connect_seq)); + if (con->v1.connect_seq != le32_to_cpu(con->v1.in_reply.connect_seq)) { + pr_err("%s%lld %s connect_seq mismatch, expected %u, got %u\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr), + con->v1.connect_seq, + le32_to_cpu(con->v1.in_reply.connect_seq)); + con->error_msg = "connect_seq mismatch"; + return -1; + } if (con->v1.in_reply.flags & CEPH_MSG_CONNECT_LOSSY) ceph_con_flag_set(con, CEPH_CON_F_LOSSYTX); diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c index 05f6eea29..966a5f800 100644 --- a/net/ceph/messenger_v2.c +++ b/net/ceph/messenger_v2.c @@ -2237,9 +2237,16 @@ static int process_hello(struct ceph_connection *con, void *p, void *end) __func__, con, ceph_pr_addr(my_addr)); } - WARN_ON(ceph_addr_is_blank(my_addr) || ceph_addr_port(my_addr)); - WARN_ON(my_addr->type != CEPH_ENTITY_ADDR_TYPE_ANY); - WARN_ON(!my_addr->nonce); + if (ceph_addr_is_blank(my_addr) || ceph_addr_port(my_addr) || + my_addr->type != CEPH_ENTITY_ADDR_TYPE_ANY || + !my_addr->nonce) { + pr_err("%s%lld %s bad my_addr %s\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr), + ceph_pr_addr(my_addr)); + con->error_msg = "bad my_addr"; + return -EINVAL; + } /* no reset_out_kvecs() as our hello may still be pending */ ret = prepare_auth_request(con); @@ -2529,14 +2536,33 @@ static int process_server_ident(struct ceph_connection *con, con->peer_name.num = cpu_to_le64(global_id); con->v2.peer_global_seq = global_seq; con->peer_features = features; - WARN_ON(required_features & ~client->supported_features); + if (required_features & ~client->supported_features) { + pr_err("%s%lld %s missing required protocol features, my supported 0x%llx, server's required 0x%llx\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr), + client->supported_features, required_features); + con->error_msg = "missing required protocol features"; + return -EINVAL; + } con->v2.server_cookie = cookie; if (flags & CEPH_MSG_CONNECT_LOSSY) { ceph_con_flag_set(con, CEPH_CON_F_LOSSYTX); - WARN_ON(con->v2.server_cookie); + if (con->v2.server_cookie) { + pr_err("%s%lld %s server_cookie is set for lossy connection\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr)); + con->error_msg = "server_cookie is set for lossy connection"; + return -EINVAL; + } } else { - WARN_ON(!con->v2.server_cookie); + if (!con->v2.server_cookie) { + pr_err("%s%lld %s server_cookie is not set for lossless connection\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr)); + con->error_msg = "server_cookie is not set for lossless connection"; + return -EINVAL; + } } clear_in_sign_kvecs(con); @@ -2618,7 +2644,14 @@ static int process_session_retry(struct ceph_connection *con, ceph_decode_64_safe(&p, end, connect_seq, bad); dout("%s con %p connect_seq %llu\n", __func__, con, connect_seq); - WARN_ON(connect_seq <= con->v2.connect_seq); + if (connect_seq <= con->v2.connect_seq) { + pr_err("%s%lld %s connect_seq mismatch, expected > %llu, got %llu\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr), + con->v2.connect_seq, connect_seq); + con->error_msg = "connect_seq mismatch"; + return -EINVAL; + } con->v2.connect_seq = connect_seq + 1; free_conn_bufs(con); @@ -2651,7 +2684,14 @@ static int process_session_retry_global(struct ceph_connection *con, ceph_decode_64_safe(&p, end, global_seq, bad); dout("%s con %p global_seq %llu\n", __func__, con, global_seq); - WARN_ON(global_seq <= con->v2.global_seq); + if (global_seq <= con->v2.global_seq) { + pr_err("%s%lld %s global_seq mismatch, expected > %llu, got %llu\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr), + con->v2.global_seq, global_seq); + con->error_msg = "global_seq mismatch"; + return -EINVAL; + } con->v2.global_seq = ceph_get_global_seq(con->msgr, global_seq); free_conn_bufs(con); base-commit: 075b74841bd0065a3bda3440873c747938e69b68 -- This is an AI-generated patch subject to moderation. Reply with '#syz upstream' to Sign-off the patch as a human author and send it to the upstream kernel mailing lists. Reply with '#syz reject' to reject it ('#syz unreject' to undo). See https://goo.gle/syzbot-ai-patches for information about AI-generated patches. The person who has signed off on the patch is responsible for addressing comments. syzbot engineers can be reached at syzkaller@googlegroups.com.