Commit 321f7798 authored by Benjamin Tissoires's avatar Benjamin Tissoires
Browse files

selftests/hid: Add HIDIOCREVOKE tests



Add 4 tests for the new revoke ioctl, for read/write/ioctl and poll.

Reviewed-by: default avatarPeter Hutterer <peter.hutterer@who-t.net>
Link: https://patch.msgid.link/20240827-hidraw-revoke-v5-4-d004a7451aea@kernel.org


Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
parent 8163892a
Loading
Loading
Loading
Loading
+147 −0
Original line number Diff line number Diff line
@@ -3,6 +3,11 @@

#include "hid_common.h"

/* for older kernels */
#ifndef HIDIOCREVOKE
#define HIDIOCREVOKE	      _IOW('H', 0x0D, int) /* Revoke device access */
#endif /* HIDIOCREVOKE */

FIXTURE(hidraw) {
	int dev_id;
	int uhid_fd;
@@ -84,6 +89,148 @@ TEST_F(hidraw, raw_event)
	ASSERT_EQ(buf[1], 42);
}

/*
 * After initial opening/checks of hidraw, revoke the hidraw
 * node and check that we can not read any more data.
 */
TEST_F(hidraw, raw_event_revoked)
{
	__u8 buf[10] = {0};
	int err;

	/* inject one event */
	buf[0] = 1;
	buf[1] = 42;
	uhid_send_event(_metadata, self->uhid_fd, buf, 6);

	/* read the data from hidraw */
	memset(buf, 0, sizeof(buf));
	err = read(self->hidraw_fd, buf, sizeof(buf));
	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
	ASSERT_EQ(buf[0], 1);
	ASSERT_EQ(buf[1], 42);

	/* call the revoke ioctl */
	err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
	ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");

	/* inject one other event */
	buf[0] = 1;
	buf[1] = 43;
	uhid_send_event(_metadata, self->uhid_fd, buf, 6);

	/* read the data from hidraw */
	memset(buf, 0, sizeof(buf));
	err = read(self->hidraw_fd, buf, sizeof(buf));
	ASSERT_EQ(err, -1) TH_LOG("read_hidraw");
	ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while reading the hidraw node: %d",
					errno);
}

/*
 * Revoke the hidraw node and check that we can not do any ioctl.
 */
TEST_F(hidraw, ioctl_revoked)
{
	int err, desc_size = 0;

	/* call the revoke ioctl */
	err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
	ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");

	/* do an ioctl */
	err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);
	ASSERT_EQ(err, -1) TH_LOG("ioctl_hidraw");
	ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while doing an ioctl: %d",
					errno);
}

/*
 * Setup polling of the fd, and check that revoke works properly.
 */
TEST_F(hidraw, poll_revoked)
{
	struct pollfd pfds[1];
	__u8 buf[10] = {0};
	int err, ready;

	/* setup polling */
	pfds[0].fd = self->hidraw_fd;
	pfds[0].events = POLLIN;

	/* inject one event */
	buf[0] = 1;
	buf[1] = 42;
	uhid_send_event(_metadata, self->uhid_fd, buf, 6);

	while (true) {
		ready = poll(pfds, 1, 5000);
		ASSERT_EQ(ready, 1) TH_LOG("poll return value");

		if (pfds[0].revents & POLLIN) {
			memset(buf, 0, sizeof(buf));
			err = read(self->hidraw_fd, buf, sizeof(buf));
			ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
			ASSERT_EQ(buf[0], 1);
			ASSERT_EQ(buf[1], 42);

			/* call the revoke ioctl */
			err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
			ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
		} else {
			break;
		}
	}

	ASSERT_TRUE(pfds[0].revents & POLLHUP);
}

/*
 * After initial opening/checks of hidraw, revoke the hidraw
 * node and check that we can not read any more data.
 */
TEST_F(hidraw, write_event_revoked)
{
	struct timespec time_to_wait;
	__u8 buf[10] = {0};
	int err;

	/* inject one event from hidraw */
	buf[0] = 1; /* report ID */
	buf[1] = 2;
	buf[2] = 42;

	pthread_mutex_lock(&uhid_output_mtx);

	memset(output_report, 0, sizeof(output_report));
	clock_gettime(CLOCK_REALTIME, &time_to_wait);
	time_to_wait.tv_sec += 2;

	err = write(self->hidraw_fd, buf, 3);
	ASSERT_EQ(err, 3) TH_LOG("unexpected error while writing to hidraw node: %d", err);

	err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);
	ASSERT_OK(err) TH_LOG("error while calling waiting for the condition");

	ASSERT_EQ(output_report[0], 1);
	ASSERT_EQ(output_report[1], 2);
	ASSERT_EQ(output_report[2], 42);

	/* call the revoke ioctl */
	err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
	ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");

	/* inject one other event */
	buf[0] = 1;
	buf[1] = 43;
	err = write(self->hidraw_fd, buf, 3);
	ASSERT_LT(err, 0) TH_LOG("unexpected success while writing to hidraw node: %d", err);
	ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while writing to hidraw node: %d",
					errno);

	pthread_mutex_unlock(&uhid_output_mtx);
}

int main(int argc, char **argv)
{
	return test_harness_run(argc, argv);