drivers/misc/lkdtm/usercopy.c

Source file repositories/reference/linux-study-clean/drivers/misc/lkdtm/usercopy.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/lkdtm/usercopy.c
Extension
.c
Size
12327 bytes
Lines
458
Domain
Driver Families
Bucket
drivers/misc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (copy_to_user(test_user_addr, test_kern_addr, size / 2)) {
			pr_warn("copy_to_user failed unexpectedly?!\n");
			goto free_user;
		}

		pr_info("attempting bad copy_to_user of too large size\n");
		if (copy_to_user(test_user_addr, test_kern_addr, size)) {
			pr_warn("copy_to_user failed, but lacked Oops\n");
			goto free_user;
		}
	} else {
		pr_info("attempting good copy_from_user of correct size\n");
		if (copy_from_user(test_kern_addr, test_user_addr, size / 2)) {
			pr_warn("copy_from_user failed unexpectedly?!\n");
			goto free_user;
		}

		pr_info("attempting bad copy_from_user of too large size\n");
		if (copy_from_user(test_kern_addr, test_user_addr, size)) {
			pr_warn("copy_from_user failed, but lacked Oops\n");
			goto free_user;
		}
	}
	pr_err("FAIL: bad usercopy not detected!\n");
	pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy");

free_user:
	vm_munmap(user_addr, PAGE_SIZE);
free_kernel:
	kfree(one);
	kfree(two);
}

/*
 * This checks for the specific whitelist window within an object. If this
 * test passes, then do_usercopy_slab_size() tests will pass too.
 */
static void do_usercopy_slab_whitelist(bool to_user)
{
	unsigned long user_alloc;
	unsigned char *buf = NULL;
	unsigned char __user *user_addr;
	size_t offset, size;

	/* Make sure cache was prepared. */
	if (!whitelist_cache) {
		pr_warn("Failed to allocate kernel cache\n");
		return;
	}

	/*
	 * Allocate a buffer with a whitelisted window in the buffer.
	 */
	buf = kmem_cache_alloc(whitelist_cache, GFP_KERNEL);
	if (!buf) {
		pr_warn("Failed to allocate buffer from whitelist cache\n");
		goto free_alloc;
	}

	/* Allocate user memory we'll poke at. */
	user_alloc = vm_mmap(NULL, 0, PAGE_SIZE,
			    PROT_READ | PROT_WRITE | PROT_EXEC,
			    MAP_ANONYMOUS | MAP_PRIVATE, 0);
	if (user_alloc >= TASK_SIZE) {
		pr_warn("Failed to allocate user memory\n");
		goto free_alloc;
	}
	user_addr = (void __user *)user_alloc;

	memset(buf, 'B', cache_size);

	/* Whitelisted window in buffer, from kmem_cache_create_usercopy. */
	offset = (cache_size / 4) + unconst;
	size = (cache_size / 16) + unconst;

	if (to_user) {
		pr_info("attempting good copy_to_user inside whitelist\n");
		if (copy_to_user(user_addr, buf + offset, size)) {
			pr_warn("copy_to_user failed unexpectedly?!\n");
			goto free_user;
		}

		pr_info("attempting bad copy_to_user outside whitelist\n");
		if (copy_to_user(user_addr, buf + offset - 1, size)) {
			pr_warn("copy_to_user failed, but lacked Oops\n");
			goto free_user;
		}
	} else {
		pr_info("attempting good copy_from_user inside whitelist\n");
		if (copy_from_user(buf + offset, user_addr, size)) {

Annotation

Implementation Notes