If you are writing your first Linux device driver, sooner or later you will need to move data between kernel space and user space. This is exactly where copy_to_user and copy_from_user in Linux kernel programming become essential. These two functions are the safe, standard way for a driver to exchange data with an application running in user space, and understanding them properly will save you from some of the most common and dangerous bugs in kernel development.
In this lesson, part of our free Linux kernel programming course, we will build a clear mental model of why direct pointer access between kernel and user space is unsafe, how the kernel protects itself, and how to use these copy routines correctly in a driver running on a modern Linux kernel.
What You Will Learn
- Why a kernel driver cannot simply dereference a user space pointer
- How copy_to_user() and copy_from_user() protect the kernel from invalid memory access
- The exact function signatures and return value conventions used on current kernels
- How to write a correct, original read and write method using these functions
- Common mistakes beginners make and how to avoid them
- Security and performance considerations when copying data across the user-kernel boundary
Prerequisites
Before starting this lesson, you should be comfortable with:
- Basic C programming, including pointers and structures
- How to compile and load a simple loadable kernel module
- Basic file operations in Linux (open, read, write, close)
Why Can’t a Driver Just Use memcpy()?
Inside a device driver, it is tempting to think that copying data is as simple as calling memcpy(). After all, a pointer is just a pointer, right? In reality, a pointer passed from a user space application into the kernel is a user space virtual address. It is only meaningful inside that particular process’s page tables. The kernel runs with its own address space mapping, and a raw memcpy() call has no way to verify that the user space address is valid, mapped, or that the calling process actually has permission to access it.
If the kernel blindly trusted every pointer handed to it by user space, a buggy or malicious application could pass in an invalid, unmapped, or even kernel-space address and potentially crash the system or leak sensitive kernel memory. This is precisely the security boundary that copy_to_user and copy_from_user in Linux kernel code are designed to enforce.
|
User Space Application buffer (untrusted address) |
→ |
Boundary Check copy_from_user() / copy_to_user() |
→ |
Kernel Space Driver buffer (trusted memory) |
The copy_to_user() and copy_from_user() Functions
Both functions live in linux/uaccess.h and share a similar three-argument pattern, much like a standard memcpy(). Their job is to safely walk through the process page tables, verify the user address range, and only then perform the actual copy.
Function Signatures
#include <linux/uaccess.h>
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n);
Notice the __user annotation. This is a sparse checker hint, not a real C keyword, but it documents that the pointer refers to user space memory. It helps catch accidental misuse during static analysis, and you should always mark user pointers this way in your own driver code.
Understanding the Return Value
Both functions return the number of bytes that could not be copied. This trips up many beginners because it is easy to assume a non-zero return means success, similar to some POSIX system calls. The convention here is the opposite:
| Return Value | Meaning |
|---|---|
| 0 | All requested bytes were copied successfully |
| Non-zero | That many bytes were left uncopied; treat this as a fault |
When the return value is non-zero, the correct driver behaviour is to return -EFAULT to user space, which maps to the familiar “Bad address” errno.
A Fresh Example: Writing a Read Method
Let’s build an original example of a character driver’s read callback. This driver keeps a small in-kernel greeting buffer and copies it out to whichever application calls read() on the device node.
#define GREETING_LEN 32
static char greeting_buf[GREETING_LEN] = "Hello from EmbeddedPathashala!";
static ssize_t greet_read(struct file *filp, char __user *user_buf,
size_t count, loff_t *offset)
{
size_t remaining, to_copy;
unsigned long not_copied;
if (*offset >= GREETING_LEN)
return 0; /* end of file reached */
remaining = GREETING_LEN - *offset;
to_copy = min(count, remaining);
not_copied = copy_to_user(user_buf, greeting_buf + *offset, to_copy);
if (not_copied)
return -EFAULT;
*offset += to_copy;
return to_copy;
}
Notice how the function tracks the file offset, calculates how many bytes are still available, and only then hands control to copy_to_user(). This mirrors exactly what a real block or character device would need to do to support repeated read() calls until end of file.
A Fresh Example: Writing a Write Method
The write path uses copy_from_user() and needs similar care, especially around buffer size limits to avoid overflowing kernel memory.
#define MAX_INPUT 64
static char input_buf[MAX_INPUT];
static ssize_t greet_write(struct file *filp, const char __user *user_buf,
size_t count, loff_t *offset)
{
size_t bytes_to_take = min(count, (size_t)(MAX_INPUT - 1));
unsigned long not_copied;
not_copied = copy_from_user(input_buf, user_buf, bytes_to_take);
if (not_copied)
return -EFAULT;
input_buf[bytes_to_take] = '\0';
pr_info("greet_driver: received %zu bytes from user space\n", bytes_to_take);
return bytes_to_take;
}
Always clamp the incoming size against your kernel buffer’s real capacity before calling copy_from_user(). Trusting the count argument blindly is a classic source of kernel buffer overflows.
Why These Functions Can Sleep
An important and often overlooked detail is that copy_to_user() and copy_from_user() may trigger a page fault while walking user space memory, and handling that fault can put the calling process to sleep. This means these functions are only safe to call from a normal process context, never from an atomic context such as inside a spinlock, a tasklet, or an interrupt handler.
|
Safe Process context (read/write/ioctl callbacks) |
Unsafe Interrupt handlers, atomic or spinlock context |
Common Mistakes and Troubleshooting
| Mistake | Why It’s a Problem |
|---|---|
| Checking for a non-zero return as success | The convention is reversed compared to typical syscalls; non-zero means failure |
Not clamping count against buffer size |
Leads to kernel buffer overflows |
| Calling from interrupt context | Can sleep due to page faults, which is illegal in atomic context |
| Forgetting to null-terminate string input | Leads to reading garbage kernel memory beyond the copied bytes |
Security Considerations
Never trust the size or content coming from user space. Always validate the requested length, clamp it to your allocated buffer, and treat every byte from user space as untrusted input until proven otherwise. This discipline is one of the fundamental habits every Linux device driver developer must build early.
Performance Considerations
Because these functions can fault and involve page table walks, avoid calling them in a tight loop for very small chunks of data. Where possible, batch your data into a single kernel buffer and perform one copy operation per system call rather than many small ones.
Best Practices Checklist
- Always check the return value and translate a non-zero result to
-EFAULT - Clamp user-supplied lengths against your kernel buffer size
- Never call these functions outside process context
- Mark user space pointers with
__userfor static analysis clarity - Track the file offset correctly to support multiple sequential reads
Summary and Key Takeaways
- copy_to_user and copy_from_user in Linux kernel code exist to safely cross the user-kernel memory boundary
- A return value of zero means success; non-zero means some bytes failed and you should return
-EFAULT - These functions may sleep, so they belong only in process context
- Always validate and clamp user-supplied sizes before copying
Conclusion
Mastering copy_to_user and copy_from_user in Linux kernel driver code is one of the first real milestones on the path to writing safe, production-quality device drivers. Once this boundary-crossing pattern feels natural, you are ready to build complete character drivers that read and write real data, which is exactly what we cover next in this free Linux device drivers course.
Frequently Asked Questions
1. What happens if I use memcpy() instead of copy_to_user()?
It may work by accident on some systems, but it bypasses the address validation the kernel relies on and can crash the system or corrupt memory when given an invalid user pointer.
2. Does a return value of 0 always mean total success?
Yes, for both functions a return of 0 means every requested byte was copied. Any non-zero value tells you how many bytes were not copied.
3. Can I call copy_from_user() inside a spinlock?
No. These functions can sleep due to page faults, and sleeping while holding a spinlock is not allowed. Copy your data before acquiring the lock, or after releasing it.
4. What error code should my driver return on a copy failure?
Return -EFAULT, which is the standard convention for a bad address error surfaced to user space as errno.
5. Why do I see a __user annotation on some pointers?
It is a sparse static analysis marker showing that a pointer refers to user space memory. It has no runtime effect but helps catch accidental misuse during code review or automated checks.
6. Is it safe to copy a large buffer, like several megabytes, in one call?
It is technically possible, but very large single copies can hold the CPU longer than desired. Many drivers chunk large transfers into smaller pieces, especially for character devices.
7. Do these functions work the same way on all recent kernel versions?
The function signatures and return conventions described here are stable and consistent across current mainline kernels used in modern distributions.
This lesson is part of EmbeddedPathashala’s free Linux kernel programming and device drivers course. Practice the examples above in your own virtual machine before moving to the next lesson.

2 Comments