From nobody Sat Jul 25 19:28:28 2026 Received: from mail-qk1-f169.google.com (mail-qk1-f169.google.com [209.85.222.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E76303921E7 for ; Tue, 14 Jul 2026 11:51:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784029908; cv=none; b=gjsQLg0DmI3glD65iC4nf38OhAozf6PajekXKf2EjkbzNkjrWhtsDG+RGyhz3Uotqbe928CQNcvUgMUR0WEJ2a2EDtxaH8nSZKl9Qk4l9PH9YXWcNc8uLkeYU9Yeoeqi8sBOY8M+CqArlV9hYsQ2iZMC1RL8JTVXwa8mJ8Poccc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784029908; c=relaxed/simple; bh=JpnDZ8ql3IabuVoCGMVqUfzzVcIrlI9D12dRWum7fzY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q1jC/PYsgkq97ynduVOmdJUqFv5ifxZvATVQEx1CNGCHU2d2z6JTa9cqF0HfDiBehOLEVYQa2wcybHYSZYHCaTcRLZq/QLwaLeki0qyWDwaJEV9gY3op0Q2cOFkzGr/Ccm9l4M1/WS/lNq7BtcAG4ABQyVBf9d14FrZEmwRdeW0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CRVhmLQX; arc=none smtp.client-ip=209.85.222.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CRVhmLQX" Received: by mail-qk1-f169.google.com with SMTP id af79cd13be357-92e855da580so326936385a.1 for ; Tue, 14 Jul 2026 04:51:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784029906; x=1784634706; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=9p/+/UmywR6wfRNM0SB+tDIf7SPmlvrUuoPqzMH3Bt8=; b=CRVhmLQXuYhcFRtawFDba1mWcn4TLI7Fvbe9G0vaiskeR7OGKsIbUehmcqtEQgN4lc xs6aKQQ7ivcDrDSwcR/OyRfAkJvdmBLGPftqJ+NwhhWfRyzHWGDNCfLaUFHCU8cj3Q/l cscvRFLY0Tl3/T1y/huqIlDBtp/HI39b9retGyyQHhYB7tXUdx4XiOHvhs0KqcXuO8CP P6IlLNR/dPVkVFYtIRGOHbdug6FtMmdL1vEprxRMktiJT6D0lCRygE11p7LrwU3kVYRU WIn28rmJAqZCFsxc6PYI7XMtrbOYwTTGn6IOAP5kxIu8FWEUujEi8tDgMUK73jSWcWD4 OxVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784029906; x=1784634706; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=9p/+/UmywR6wfRNM0SB+tDIf7SPmlvrUuoPqzMH3Bt8=; b=jO77kw/6DWpSRPA/Mdn0Vh9DqLankkiSGowz1ho5SQQLgzwsELBcn+IzSNVe9NpZda d5G/5j7N4MCh7fUeMrpMGNtrXDYVpIaRJv/aD+Q0qDHt6SEGyC2yDJOLM5KZQ2EK8wJl eLv6RwzG1ldttBiiumurb0Xn9Tm1pHUczaCYSTtsFLQEvIXwGAk8qsK3Xc4TdqRx13P9 A9Khlk5tO3XHSrm9DrneoB7Axis0AqxLCLmcAhWLIlVK0PkO8XBo/BO4RRLR+5QwVtoZ Vh3Ll4DGH3s1X4dcFkQsULfgV+FH1TBNB6fx8DPtsE37muiCpb6vqOdYqtjx3FwwhbaM 51mA== X-Forwarded-Encrypted: i=1; AHgh+RqMMtTtDuyvbm81LDAUaYmRFtqvnRm+ETmcrTLOGuD1PvAqG++wKHU9bpQkeuVuqbe3G48Kyzm/cJ3tKcY=@vger.kernel.org X-Gm-Message-State: AOJu0Yzr6BCLvBcB1Qajl2IPJZ7G2y2obZncGPaHhsulVM4jZb58DNfp ZGNK0cILlwQDl9A8S1EvCUGqwWo1De8LO2CzhQlx+hh7mu7flZE7ioiSFvxHsZ+p+Ew= X-Gm-Gg: AfdE7ckr8dmsSNC6/Wby/nlRWMksj1RbHIAZ5j9dtE48eSWdFqVs/XtsDIulaibd6RI f/lSgy14c17HQ8DuT1qd4M9RW8IHQU7cOeaRsJlqQi/eTh05qggwjrM7Qhc2PuPlLc0ab6cwAGj 8MfzfHsmIOfyDg49RgltKm67o2IESO79Gi+AtIkR1wWC+eWKR8MFe23eLuosMW4e84gS2e4iX1Y x9GJ6DldovdHSfoI9za0a5hj1mCuAt87p8hSik9cqMPl2QRyQ7ObkfiO/40hNee3rzmqdYp0DIm nrEQ2MZ2oK9BJAAGKBSQVOgPMUvN1zYfXgg3OzyIRJ5thwvq1ADIhyMpq05j3qtGl3wGGf+A8fE oSpOuP6tf7e4YrR4+/Bi8Zet8n7gU0FRzF59aFAF3O4qg+74jA98VVGFUTx0m0+caUpZShjUYnD I7ro3LBTATzUmPDP9fzy6JKQh9/kFvsDpvNu/W46+WKstK9KKvy+5BC2TTCDV9wZjGRbFYTspr4 8cF9QokJg== X-Received: by 2002:a05:620a:2790:b0:92e:c117:9eae with SMTP id af79cd13be357-92ef2e57c99mr1073038685a.92.1784029905785; Tue, 14 Jul 2026 04:51:45 -0700 (PDT) Received: from server0 (c-68-48-65-54.hsd1.mi.comcast.net. [68.48.65.54]) by smtp.gmail.com with ESMTPSA id af79cd13be357-92ee5d6c28bsm1479415585a.46.2026.07.14.04.51.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Jul 2026 04:51:45 -0700 (PDT) From: Michael Bommarito To: Ilya Dryomov Cc: Viacheslav Dubeyko , ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org Subject: [PATCH v2 1/2] libceph: validate OSD extent maps before cursor advance Date: Tue, 14 Jul 2026 07:51:39 -0400 Message-ID: <20260714115141.3768034-2-michael.bommarito@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260714115141.3768034-1-michael.bommarito@gmail.com> References: <20260714115141.3768034-1-michael.bommarito@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" net/ceph/osd_client.c:osd_sparse_read() validates that the sparse-read data length matches the summed extent lengths, but it does not validate that each OSD-supplied extent is monotonic and lies inside the original request range. A malformed authenticated OSD reply can advertise a far-forward nonzero extent offset with a matching data length and make the client advance the message-data cursor beyond the request buffer. This reaches the BUG_ON(!*length) assertion in ceph_msg_data_next() from the client receive path. Impact: A malicious or compromised authenticated Ceph OSD peer can crash a kernel Ceph client via a malformed sparse-read reply. Reject sparse extent maps that overflow, move backwards, overlap, or extend outside the original sparse-read request before advancing the cursor. Fixes: f628d7999727 ("libceph: add sparse read support to OSD client") Cc: stable@vger.kernel.org Reviewed-by: Viacheslav Dubeyko Assisted-by: Codex:gpt-5-5-xhigh Signed-off-by: Michael Bommarito Reviewed-by. Patch 2 adds the KUnit coverage he asked for. --- net/ceph/osd_client.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 2ff00070c1810..76ba3abdad9b1 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -5799,6 +5800,31 @@ static inline void convert_extent_map(struct ceph_sp= arse_read *sr) } #endif =20 +static bool sparse_extent_map_valid(struct ceph_sparse_read *sr) +{ + u64 req_end, pos; + int i; + + if (check_add_overflow(sr->sr_req_off, sr->sr_req_len, &req_end)) + return false; + + pos =3D sr->sr_req_off; + for (i =3D 0; i < sr->sr_count; i++) { + struct ceph_sparse_extent *ext =3D &sr->sr_extent[i]; + u64 end; + + if (ext->off < pos) + return false; + if (check_add_overflow(ext->off, ext->len, &end)) + return false; + if (end > req_end) + return false; + pos =3D end; + } + + return true; +} + static int osd_sparse_read(struct ceph_connection *con, struct ceph_msg_data_cursor *cursor, char **pbuf) @@ -5856,6 +5882,10 @@ static int osd_sparse_read(struct ceph_connection *c= on, case CEPH_SPARSE_READ_DATA_PRE: /* Convert sr_datalen to host-endian */ sr->sr_datalen =3D le32_to_cpu((__force __le32)sr->sr_datalen); + if (!sparse_extent_map_valid(sr)) { + pr_warn_ratelimited("invalid sparse extent map\n"); + return -EREMOTEIO; + } for (i =3D 0; i < count; i++) len +=3D sr->sr_extent[i].len; if (sr->sr_datalen !=3D len) { --=20 2.53.0 From nobody Sat Jul 25 19:28:28 2026 Received: from mail-qk1-f176.google.com (mail-qk1-f176.google.com [209.85.222.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3C7533932FA for ; Tue, 14 Jul 2026 11:51:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784029909; cv=none; b=HMrIDQs2lX05gmXHwkF0MiUkcP8e12SQjHpFreKJ3msuAVD0XrOtZke7B5I6goiLynckTcVYcx33Qe96mz8NVO/GrEV1UV1BbZ6FExFibC/5PdmU5nsbfylT2IIruw5Q/rpP2QDjrodgso+kGGRW7biHd1xI6oIYelY6YxDDUKo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784029909; c=relaxed/simple; bh=p2+stEBi4BElrza3ht2ZDPtC7TCuwqQDOOPe33VgEbE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rx5cYchp1gNiVxGEF8SrMWeHRcDkDYQj1+ul50H3imFwhAew9jkJIoiHpCPWhVanlYMOrXipeb6t8j1dViuqysS0lrp6ymgHwyHrHsid4lslsau+GLkbhwRhHZCkH8iy0jYZe+3qUoX0Klft5rxCBsTxgtdZ4FrfemZoJu0mbx4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=o9nPdpiy; arc=none smtp.client-ip=209.85.222.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="o9nPdpiy" Received: by mail-qk1-f176.google.com with SMTP id af79cd13be357-92e5d6f35c1so334309285a.0 for ; Tue, 14 Jul 2026 04:51:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784029907; x=1784634707; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Y3h+GE7dRUK0jTaidLd+LkoAa9P1Kl0QyikD71h1Zag=; b=o9nPdpiyiWXVHL+eDWUnoXmzHcjcAMp5jc7cjAFEfNb9VytbgL2UY0hJ9AUZ4QKvqY cXCJB5oXzLiB2NLov8NP1jHW7m+aiy5JKgEkivx830ryj95sieaNbfglAxojSXdqVmZr dPsoQ47rHBjEkLKhGuhK79aR3PJfptT3HUpl/Fa56VJk+Bp3tmHk/t28OloJ8+VrVXZ6 9HvqLb+6seXlOeJR/jnWsRk1sgufNEJQHSJ9JAB7kZ9/xWIgF1h+vRRIDN2WT+2eOVRc DMHOpeYu/z7nXyOLov2dh/nFvtIyJJzZTn9qPpVqlsuhay5wBzyWv+UcyPGkg9bCRfS8 KGeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784029907; x=1784634707; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Y3h+GE7dRUK0jTaidLd+LkoAa9P1Kl0QyikD71h1Zag=; b=kuBakXdg0mFeU2PX7KIqBQWCpQ0fTZzjJH/qdjaZ3LO892YMQjUFfUMXEKrTxbsw9Q nHhvHM4QLdhp9dlPxLOphC00qV1l3zEf1Vp3rJFF40/JT60pyPoeOMIUvNEev2LME9m6 QqyxswdORaiC5Q6qLsmavAUhnQx/6Tp3YljuBfB0Clt3/sdo+54b87pMSelGOQSS5d0/ Sp/pBBX1nGQ5L38Y8JuZY1r7IBYtFlFNZgVxsxmv3etapXWojdiB7tEV6Sxaz2CcCI7G 25Pqq9Ugi1zNjm4zPQDz+/r09UW3fNWzQzZp2rSqHXP6ZSChCi8vG+/W+iQqOJLOLfKw YMJg== X-Forwarded-Encrypted: i=1; AHgh+Roxyo6YaxD+s2A0MA2dZUvmKNjmIaeM5Nxm0+Kuw8+LW3d5plCPK+DHB6EwWyXbJ4oM8E7HTXVKRuKf/Qw=@vger.kernel.org X-Gm-Message-State: AOJu0YzG0tDuBiHMMJBM4CC5EheqnhOpcK+5YshIWso6xHJtix+wv7zL 7N5xf33cOuYKuUoP3RB2E0UGVtDTIvW5EPnKiqeG6ul8h/xOjwctbX2S X-Gm-Gg: AfdE7cnqIGF+myB0P/zGbUOFtxPnPsPw535RiIayx9KepHftltiVoLJ78334mGVVESs 6+dwi/f9agVQ/T5RuZqnIkjysvaxKFEa4/IHtBfqmofLD26Iw2pLLkqsZAdBIJV5D6qjEG07JGf W6Nyz1eV20Tsu0I3dWG18j/Z4kUCIdIebdmiRsRYl04gwFUjDYx4HsFzYSJTWYlYAL00p3BxbWd eT48OczgQQ5VaUaN03c9zvQZZMzbEvj8SL36ivWVU7d4NlcDrvSzoUrZ3HEXJCooJoFNPxU3Aoy 68oMi2NY6dishD36Tf2BQ5yvcGXtwMtfU0PivhLsom9Aa4yXIy8U4xFsUVuuHAlZgsp2/s8ZAm2 rUNpJuelh/Ffg9ddlH3fDpuVnElrM/mD1WJmXdz4LcestG6pciARAv4sn5IFuzxPegbH0Y0fSBP v9bjrgC0dDnQX2d1pxOFs88x3B4N+g2zDC5KAPjcr83lp3d9dpGHwpi2H3ETnTFtTsxZZYtpY0F NQakh0yHQ== X-Received: by 2002:a05:620a:a1c5:b0:92b:6805:91bc with SMTP id af79cd13be357-92ef2c83ec3mr1042554585a.68.1784029907021; Tue, 14 Jul 2026 04:51:47 -0700 (PDT) Received: from server0 (c-68-48-65-54.hsd1.mi.comcast.net. [68.48.65.54]) by smtp.gmail.com with ESMTPSA id af79cd13be357-92ee5d6c28bsm1479415585a.46.2026.07.14.04.51.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Jul 2026 04:51:46 -0700 (PDT) From: Michael Bommarito To: Ilya Dryomov Cc: Viacheslav Dubeyko , ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org Subject: [PATCH v2 2/2] libceph: add KUnit coverage for OSD sparse-read extent validation Date: Tue, 14 Jul 2026 07:51:40 -0400 Message-ID: <20260714115141.3768034-3-michael.bommarito@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260714115141.3768034-1-michael.bommarito@gmail.com> References: <20260714115141.3768034-1-michael.bommarito@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add KUnit coverage for the sparse-read extent-map validation added by the previous patch. The tests drive the real osd_sparse_read() state machine over a synthesized OSD reply (no OSD or network): an in-range single extent is accepted and advances the cursor, and an extent whose offset lies outside the original request range is rejected with -EREMOTEIO before the message-data cursor is advanced. The suite is included from osd_client.c so it can exercise the static sparse-read parser and cursor-advance helpers without exporting test-only symbols, guarded by CONFIG_CEPH_LIB_KUNIT_TEST. Assisted-by: Codex:gpt-5-5-xhigh Signed-off-by: Michael Bommarito Reviewed-by. Patch 2 adds the KUnit coverage he asked for. --- net/ceph/Kconfig | 12 +++ net/ceph/osd_client-kunit.c | 146 ++++++++++++++++++++++++++++++++++++ net/ceph/osd_client.c | 4 + 3 files changed, 162 insertions(+) create mode 100644 net/ceph/osd_client-kunit.c diff --git a/net/ceph/Kconfig b/net/ceph/Kconfig index 7e2528cde4b94..6b78fe4a0f8a4 100644 --- a/net/ceph/Kconfig +++ b/net/ceph/Kconfig @@ -45,3 +45,15 @@ config CEPH_LIB_USE_DNS_RESOLVER Documentation/networking/dns_resolver.rst =20 If unsure, say N. + +config CEPH_LIB_KUNIT_TEST + bool "KUnit tests for the Ceph core library" if !KUNIT_ALL_TESTS + depends on CEPH_LIB && KUNIT + default KUNIT_ALL_TESTS + help + This builds KUnit coverage for selected Ceph core-library parser + and state-machine helpers. The tests exercise internal libceph + behavior with synthesized state and are intended for developer + validation rather than production systems. + + If unsure, say N. diff --git a/net/ceph/osd_client-kunit.c b/net/ceph/osd_client-kunit.c new file mode 100644 index 0000000000000..713f24675f68f --- /dev/null +++ b/net/ceph/osd_client-kunit.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit coverage for net/ceph/osd_client.c internals. + * + * Included from osd_client.c so the test can drive the real static sparse= -read + * parser and cursor-advance helper without exporting test-only symbols. + */ + +#include + +struct ceph_osd_sparse_read_test { + struct ceph_osd osd; + struct ceph_connection con; + struct ceph_msg *msg; + struct ceph_msg_data_cursor cursor; + struct ceph_osd_request *req; + struct page **pages; + struct page *page; +}; + +static int ceph_osd_sparse_read_test_init(struct kunit *test) +{ + struct ceph_osd_sparse_read_test *ctx; + + ctx =3D kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + ctx->req =3D kunit_kzalloc(test, struct_size(ctx->req, r_ops, 1), + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->req); + + ctx->pages =3D kunit_kcalloc(test, 1, sizeof(*ctx->pages), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->pages); + + ctx->page =3D alloc_page(GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->page); + ctx->pages[0] =3D ctx->page; + + ctx->msg =3D ceph_msg_new2(CEPH_MSG_OSD_OPREPLY, 0, 1, GFP_KERNEL, true); + KUNIT_ASSERT_NOT_NULL(test, ctx->msg); + + osd_init(&ctx->osd); + ctx->osd.o_sparse_op_idx =3D -1; + ceph_init_sparse_read(&ctx->osd.o_sparse_read); + + request_init(ctx->req); + ctx->req->r_tid =3D 1; + ctx->req->r_num_ops =3D 1; + osd_req_op_extent_init(ctx->req, 0, CEPH_OSD_OP_SPARSE_READ, + 0, PAGE_SIZE, 0, 0); + KUNIT_ASSERT_EQ(test, ctx->req->r_ops[0].op, CEPH_OSD_OP_SPARSE_READ); + + insert_request(&ctx->osd.o_requests, ctx->req); + + ctx->msg->hdr.tid =3D cpu_to_le64(ctx->req->r_tid); + ceph_msg_data_add_pages(ctx->msg, ctx->pages, PAGE_SIZE, 0, false); + ceph_msg_data_cursor_init(&ctx->cursor, ctx->msg, PAGE_SIZE); + + ctx->con.private =3D &ctx->osd; + ctx->con.in_msg =3D ctx->msg; + + test->priv =3D ctx; + return 0; +} + +static void ceph_osd_sparse_read_test_exit(struct kunit *test) +{ + struct ceph_osd_sparse_read_test *ctx =3D test->priv; + + if (!ctx) + return; + + if (ctx->req && !RB_EMPTY_NODE(&ctx->req->r_node)) + erase_request(&ctx->osd.o_requests, ctx->req); + ceph_init_sparse_read(&ctx->osd.o_sparse_read); + if (ctx->msg) + ceph_msg_put(ctx->msg); + if (ctx->page) + __free_page(ctx->page); +} + +static int ceph_osd_sparse_read_feed_one_extent(struct kunit *test, + u64 off, u64 len, u32 datalen) +{ + struct ceph_osd_sparse_read_test *ctx =3D test->priv; + struct ceph_sparse_read *sr =3D &ctx->osd.o_sparse_read; + char *buf =3D NULL; + int ret; + + ret =3D osd_sparse_read(&ctx->con, &ctx->cursor, &buf); + KUNIT_ASSERT_EQ(test, ret, (int)sizeof(sr->sr_count)); + KUNIT_ASSERT_PTR_EQ(test, buf, (char *)&sr->sr_count); + + sr->sr_count =3D (__force u32)cpu_to_le32(1); + ret =3D osd_sparse_read(&ctx->con, &ctx->cursor, &buf); + KUNIT_ASSERT_EQ(test, ret, (int)sizeof(*sr->sr_extent)); + KUNIT_ASSERT_NOT_NULL(test, sr->sr_extent); + KUNIT_ASSERT_PTR_EQ(test, buf, (char *)sr->sr_extent); + + sr->sr_extent[0].off =3D (__force u64)cpu_to_le64(off); + sr->sr_extent[0].len =3D (__force u64)cpu_to_le64(len); + ret =3D osd_sparse_read(&ctx->con, &ctx->cursor, &buf); + KUNIT_ASSERT_EQ(test, ret, (int)sizeof(sr->sr_datalen)); + KUNIT_ASSERT_PTR_EQ(test, buf, (char *)&sr->sr_datalen); + + sr->sr_datalen =3D (__force u32)cpu_to_le32(datalen); + return osd_sparse_read(&ctx->con, &ctx->cursor, &buf); +} + +static void ceph_osd_sparse_read_in_range_extent(struct kunit *test) +{ + struct ceph_osd_sparse_read_test *ctx =3D test->priv; + struct ceph_sparse_read *sr =3D &ctx->osd.o_sparse_read; + int ret; + + ret =3D ceph_osd_sparse_read_feed_one_extent(test, 0, 16, 16); + + KUNIT_EXPECT_EQ(test, ret, 16); + KUNIT_EXPECT_EQ(test, sr->sr_pos, 16); + KUNIT_EXPECT_EQ(test, ctx->cursor.sr_resid, 16); + KUNIT_EXPECT_EQ(test, ctx->cursor.resid, PAGE_SIZE); +} + +static void ceph_osd_sparse_read_rejects_out_of_range_extent(struct kunit = *test) +{ + int ret; + + ret =3D ceph_osd_sparse_read_feed_one_extent(test, PAGE_SIZE + 16, 16, 16= ); + + KUNIT_EXPECT_EQ(test, ret, -EREMOTEIO); +} + +static struct kunit_case ceph_osd_sparse_read_test_cases[] =3D { + KUNIT_CASE(ceph_osd_sparse_read_in_range_extent), + KUNIT_CASE(ceph_osd_sparse_read_rejects_out_of_range_extent), + {} +}; + +static struct kunit_suite ceph_osd_sparse_read_test_suite =3D { + .name =3D "ceph_osd_sparse_read", + .init =3D ceph_osd_sparse_read_test_init, + .exit =3D ceph_osd_sparse_read_test_exit, + .test_cases =3D ceph_osd_sparse_read_test_cases, +}; + +kunit_test_suite(ceph_osd_sparse_read_test_suite); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 76ba3abdad9b1..b9ab9608ec88e 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -5951,3 +5951,7 @@ static const struct ceph_connection_operations osd_co= n_ops =3D { .handle_auth_done =3D osd_handle_auth_done, .handle_auth_bad_method =3D osd_handle_auth_bad_method, }; + +#ifdef CONFIG_CEPH_LIB_KUNIT_TEST +#include "osd_client-kunit.c" +#endif --=20 2.53.0