mm/usercopy.c

Source file repositories/reference/linux-study-clean/mm/usercopy.c

File Facts

System
Linux kernel
Corpus path
mm/usercopy.c
Extension
.c
Size
8608 bytes
Lines
288
Domain
Core OS
Bucket
Memory Management
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (n > area->va_end - addr) {
			offset = addr - area->va_start;
			usercopy_abort("vmalloc", NULL, to_user, offset, n);
		}
		return;
	}

	if (!virt_addr_valid(ptr))
		return;

	page = virt_to_page(ptr);
	slab = page_slab(page);
	if (slab) {
		/* Check slab allocator for flags and size. */
		__check_heap_object(ptr, n, slab, to_user);
	} else if (PageCompound(page)) {
		page = compound_head(page);
		offset = ptr - page_address(page);
		if (n > page_size(page) - offset)
			usercopy_abort("page alloc", NULL, to_user, offset, n);
	}

	/*
	 * We cannot check non-compound pages.  They might be part of
	 * a large allocation, in which case crossing a page boundary
	 * is fine.
	 */
}

DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_HARDENED_USERCOPY_DEFAULT_ON,
			   validate_usercopy_range);
EXPORT_SYMBOL(validate_usercopy_range);

/*
 * Validates that the given object is:
 * - not bogus address
 * - fully contained by stack (or stack frame, when available)
 * - fully within SLAB object (or object whitelist area, when available)
 * - not in kernel text
 */
void __check_object_size(const void *ptr, unsigned long n, bool to_user)
{
	/* Skip all tests if size is zero. */
	if (!n)
		return;

	/* Check for invalid addresses. */
	check_bogus_address((const unsigned long)ptr, n, to_user);

	/* Check for bad stack object. */
	switch (check_stack_object(ptr, n)) {
	case NOT_STACK:
		/* Object is not touching the current process stack. */
		break;
	case GOOD_FRAME:
	case GOOD_STACK:
		/*
		 * Object is either in the correct frame (when it
		 * is possible to check) or just generally on the
		 * process stack (when frame checking not available).
		 */
		return;
	default:
		usercopy_abort("process stack", NULL, to_user,
#ifdef CONFIG_ARCH_HAS_CURRENT_STACK_POINTER
			IS_ENABLED(CONFIG_STACK_GROWSUP) ?
				ptr - (void *)current_stack_pointer :
				(void *)current_stack_pointer - ptr,
#else
			0,
#endif
			n);
	}

	/* Check for bad heap object. */
	check_heap_object(ptr, n, to_user);

	/* Check for object in kernel to avoid text exposure. */
	check_kernel_text_object((const unsigned long)ptr, n, to_user);
}
EXPORT_SYMBOL(__check_object_size);

static bool enable_checks __initdata =
		IS_ENABLED(CONFIG_HARDENED_USERCOPY_DEFAULT_ON);

static int __init parse_hardened_usercopy(char *str)
{
	if (kstrtobool(str, &enable_checks))
		pr_warn("Invalid option string for hardened_usercopy: '%s'\n",
			str);

Annotation

Implementation Notes