From nobody Thu Oct 2 19:25:11 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9EE7430DD12; Fri, 12 Sep 2025 16:59:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757696340; cv=none; b=tNB96bj1o9lJWgV9APVwFhEOKxNsTDj57ndBb/4rl0CTqHrdksEVO7FskT2KdjKFoz6NFfCrL5SDdLqYxO/B+1koFYOi1WP62GPGx36Fhp4QG99gXV1NmehX9eLc2DPd6EhJhXR3HOpDnzo/yGdVxxIyr++KGlr4DQLr1N8lCt0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757696340; c=relaxed/simple; bh=IlMePipPTDazOklUtuC2COQIsM/h+CEoQ9yWVs4bDJw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AQj03S+1iIxZ47jO7RFAY42I9RnAlm5CxPtAvTT77EpMm/o0aPM3tMheTjDEY03NSmIKXvTMTUgfztlO6FHkWocGI+lZkgomhySCjQcO+K8AjVMhRT1cOnBye9ahejogst/LfI0N3SyMcutjXHI02Oci/hdp06oCxBEKh1x7FqU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Qgxi7q4K; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Qgxi7q4K" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 044CCC4CEF4; Fri, 12 Sep 2025 16:58:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1757696340; bh=IlMePipPTDazOklUtuC2COQIsM/h+CEoQ9yWVs4bDJw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Qgxi7q4KkB/q2N/2y9PwxPeIlOori9y8GnJJ/k7a6cI+hCXneMWRtojS+Oh5VyGAd 1JCc3vm7nRGI56hmfKykafVjBnO4Wc9Itxm6D5QCrPiz/c9PgFvie0/9K777rEUdO4 rWmIeZ8uiKyGTyqSh7OPzx+EYrkx7JUbov378C2xA1fjpR16v8ZW0J7AgexKMje7Sy 1H77LxfA7m2I9r6DsmadClZ0No+9QFZnJH1lVO/oYzLXmWCDDig55pK6trgQRYz98A w7H7WWbFIlWaaYPmJz3pXqngdbgsmd8cPB9OzOrC4dwgtz9mCf8/Gen5/8RsmIZudf dGNjXF3ynvD3Q== From: Benjamin Tissoires Date: Fri, 12 Sep 2025 18:58:50 +0200 Subject: [PATCH v3 2/3] selftests/hid: hidraw: forge wrong ioctls and tests them Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250912-b4-hidraw-ioctls-v3-2-cd2c6efd8c20@kernel.org> References: <20250912-b4-hidraw-ioctls-v3-0-cd2c6efd8c20@kernel.org> In-Reply-To: <20250912-b4-hidraw-ioctls-v3-0-cd2c6efd8c20@kernel.org> To: Jiri Kosina , Shuah Khan , Arnd Bergmann Cc: linux-input@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Benjamin Tissoires X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1757696335; l=5515; i=bentiss@kernel.org; s=20230215; h=from:subject:message-id; bh=IlMePipPTDazOklUtuC2COQIsM/h+CEoQ9yWVs4bDJw=; b=qsNqc+31neoyvlUgtAOtVIEq3T3gfaRnwgKXxxJcAoWtUo6FTE//fGjYaHY8RERg/o1U48XIH CdwOLBg2ZD3CJK5bau8OXWnMbf40h2ZAGBBkSKerBkCH3YhrQet5FTy X-Developer-Key: i=bentiss@kernel.org; a=ed25519; pk=7D1DyAVh6ajCkuUTudt/chMuXWIJHlv2qCsRkIizvFw= We also need coverage for when the malicious user is not using the proper ioctls definitions and tries to work around the driver. Most of the scaffholding has been generated by claude-4-sonnet and then carefully reviewed. Suggested-by: Arnd Bergmann Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/hidraw.c | 127 +++++++++++++++++++++++++++++++= ++++ 1 file changed, 127 insertions(+) diff --git a/tools/testing/selftests/hid/hidraw.c b/tools/testing/selftests= /hid/hidraw.c index 6d61d03e2ef05e1900fe5a3938d93421717b2621..d625772f8b7cf71fd94956d3a49= d54ff44e2b34d 100644 --- a/tools/testing/selftests/hid/hidraw.c +++ b/tools/testing/selftests/hid/hidraw.c @@ -332,6 +332,133 @@ TEST_F(hidraw, ioctl_gfeature_invalid) ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno); } =20 +/* + * Test ioctl with incorrect nr bits + */ +TEST_F(hidraw, ioctl_invalid_nr) +{ + char buf[256] =3D {0}; + int err; + unsigned int bad_cmd; + + /* + * craft an ioctl command with wrong _IOC_NR bits + */ + bad_cmd =3D _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is n= ot valid */ + + /* test the ioctl */ + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0) should = have failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0), got errno %d",= errno); + + /* + * craft an ioctl command with wrong _IOC_NR bits + */ + bad_cmd =3D _IOC(_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is not valid */ + + /* test the ioctl */ + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0) should h= ave failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0), got errno %d", = errno); + + /* also test with bigger number */ + bad_cmd =3D _IOC(_IOC_READ, 'H', 0x42, sizeof(buf)); /* 0x42 is not valid= as well */ + + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0x42) shoul= d have failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0x42), got errno %d= ", errno); + + /* also test with bigger number: 0x42 is not valid as well */ + bad_cmd =3D _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x42, sizeof(buf)); + + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0x42) shou= ld have failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0x42), got errno %= d", errno); +} + +/* + * Test ioctl with incorrect type bits + */ +TEST_F(hidraw, ioctl_invalid_type) +{ + char buf[256] =3D {0}; + int err; + unsigned int bad_cmd; + + /* + * craft an ioctl command with wrong _IOC_TYPE bits + */ + bad_cmd =3D _IOC(_IOC_WRITE|_IOC_READ, 'I', 0x01, sizeof(buf)); /* 'I' sh= ould be 'H' */ + + /* test the ioctl */ + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl with wrong _IOC_TYPE (I) should have fail= ed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_NR, got e= rrno %d", errno); +} + +/* + * Test HIDIOCGFEATURE ioctl with incorrect _IOC_DIR bits + */ +TEST_F(hidraw, ioctl_gfeature_invalid_dir) +{ + __u8 buf[10] =3D {0}; + int err; + unsigned int bad_cmd; + + /* set report ID 1 in first byte */ + buf[0] =3D 1; + + /* + * craft an ioctl command with wrong _IOC_DIR bits + * HIDIOCGFEATURE should have _IOC_WRITE|_IOC_READ, let's use only _IOC_W= RITE + */ + bad_cmd =3D _IOC(_IOC_WRITE, 'H', 0x07, sizeof(buf)); /* should be _IOC_W= RITE|_IOC_READ */ + + /* try to get feature report with wrong direction bits */ + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have = failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got = errno %d", errno); + + /* also test with only _IOC_READ */ + bad_cmd =3D _IOC(_IOC_READ, 'H', 0x07, sizeof(buf)); /* should be _IOC_WR= ITE|_IOC_READ */ + + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have = failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got = errno %d", errno); +} + +/* + * Test read-only ioctl with incorrect _IOC_DIR bits + */ +TEST_F(hidraw, ioctl_readonly_invalid_dir) +{ + char buf[256] =3D {0}; + int err; + unsigned int bad_cmd; + + /* + * craft an ioctl command with wrong _IOC_DIR bits + * HIDIOCGRAWNAME should have _IOC_READ, let's use _IOC_WRITE + */ + bad_cmd =3D _IOC(_IOC_WRITE, 'H', 0x04, sizeof(buf)); /* should be _IOC_R= EAD */ + + /* try to get device name with wrong direction bits */ + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have = failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got = errno %d", errno); + + /* also test with _IOC_WRITE|_IOC_READ */ + bad_cmd =3D _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x04, sizeof(buf)); /* should= be only _IOC_READ */ + + err =3D ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have = failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got = errno %d", errno); +} + /* * Test HIDIOCSFEATURE ioctl to set feature report */ --=20 2.51.0