lib/tests/usercopy_kunit.c

Source file repositories/reference/linux-study-clean/lib/tests/usercopy_kunit.c

File Facts

System
Linux kernel
Corpus path
lib/tests/usercopy_kunit.c
Extension
.c
Size
10523 bytes
Lines
337
Domain
Kernel Services
Bucket
lib
Inferred role
Kernel Services: implementation source
Status
source implementation candidate

Why This File Exists

Shared kernel service surface used by multiple subsystems, including helpers, cryptography, virtualization support, and async I/O infrastructure.

Dependency Surface

Detected Declarations

Annotated Snippet

struct usercopy_test_priv {
	char *kmem;
	char __user *umem;
	size_t size;
};

static bool is_zeroed(void *from, size_t size)
{
	return memchr_inv(from, 0x0, size) == NULL;
}

/* Test usage of check_nonzero_user(). */
static void usercopy_test_check_nonzero_user(struct kunit *test)
{
	size_t start, end, i, zero_start, zero_end;
	struct usercopy_test_priv *priv = test->priv;
	char __user *umem = priv->umem;
	char *kmem = priv->kmem;
	size_t size = priv->size;

	KUNIT_ASSERT_GE_MSG(test, size, 2 * PAGE_SIZE, "buffer too small");

	/*
	 * We want to cross a page boundary to exercise the code more
	 * effectively. We also don't want to make the size we scan too large,
	 * otherwise the test can take a long time and cause soft lockups. So
	 * scan a 1024 byte region across the page boundary.
	 */
	size = 1024;
	start = PAGE_SIZE - (size / 2);

	kmem += start;
	umem += start;

	zero_start = size / 4;
	zero_end = size - zero_start;

	/*
	 * We conduct a series of check_nonzero_user() tests on a block of
	 * memory with the following byte-pattern (trying every possible
	 * [start,end] pair):
	 *
	 *   [ 00 ff 00 ff ... 00 00 00 00 ... ff 00 ff 00 ]
	 *
	 * And we verify that check_nonzero_user() acts identically to
	 * memchr_inv().
	 */

	memset(kmem, 0x0, size);
	for (i = 1; i < zero_start; i += 2)
		kmem[i] = 0xff;
	for (i = zero_end; i < size; i += 2)
		kmem[i] = 0xff;

	KUNIT_EXPECT_EQ_MSG(test, copy_to_user(umem, kmem, size), 0,
		"legitimate copy_to_user failed");

	for (start = 0; start <= size; start++) {
		for (end = start; end <= size; end++) {
			size_t len = end - start;
			int retval = check_zeroed_user(umem + start, len);
			int expected = is_zeroed(kmem + start, len);

			KUNIT_ASSERT_EQ_MSG(test, retval, expected,
				"check_nonzero_user(=%d) != memchr_inv(=%d) mismatch (start=%zu, end=%zu)",
				retval, expected, start, end);
		}
	}
}

/* Test usage of copy_struct_from_user(). */
static void usercopy_test_copy_struct_from_user(struct kunit *test)
{
	char *umem_src = NULL, *expected = NULL;
	struct usercopy_test_priv *priv = test->priv;
	char __user *umem = priv->umem;
	char *kmem = priv->kmem;
	size_t size = priv->size;
	size_t ksize, usize;

	umem_src = kunit_kmalloc(test, size, GFP_KERNEL);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, umem_src);

	expected = kunit_kmalloc(test, size, GFP_KERNEL);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected);

	/* Fill umem with a fixed byte pattern. */
	memset(umem_src, 0x3e, size);
	KUNIT_ASSERT_EQ_MSG(test, copy_to_user(umem, umem_src, size), 0,
		    "legitimate copy_to_user failed");

Annotation

Implementation Notes