« Previous Lecture | Next Lecture »
Every character driver eventually faces the same question: how do you safely move bytes between a kernel-space buffer and a user-space application’s memory? This free Linux device drivers course lecture answers that with copy_to_user() and copy_from_user() — the two kernel APIs every driver author must understand before writing a real read or write method.
Prerequisites
This lecture builds directly on the previous one in this free Linux kernel development course, where we tested a character driver’s read and write methods using the dd command. Make sure you’re comfortable with basic character driver structure and the file_operations table before continuing.
Why You Can’t Just memcpy() User Memory
A kernel-space pointer and a user-space pointer live in completely different address spaces. Even though both look like ordinary C pointers, a kernel function cannot safely dereference a user-space pointer directly using memcpy() for two solid reasons.
The kernel solves both problems with two purpose-built inline functions: copy_to_user() for kernel-to-user transfers, and copy_from_user() for user-to-kernel transfers. Both validate the user pointer and handle the transfer in an architecture-safe way.
Function Signatures
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);
| Function | Direction | Typical Use |
|---|---|---|
copy_to_user() |
Kernel → User | Inside a driver’s read() method |
copy_from_user() |
User → Kernel | Inside a driver’s write() method |
Understanding the Return Value
Both functions return the number of bytes that could not be copied. A return value of 0 means complete success. Any non-zero value means a partial or total failure, and your driver must treat that as an error rather than ignoring it.
Full success
Partial copy — treat as error
A Complete Driver Example
Here is an original, self-contained character driver that maintains a small internal buffer and uses both APIs correctly, including proper error handling on every call:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#define DEV_NAME "epbuf_chardrv"
#define BUF_SIZE 256
static char *kbuf;
static size_t data_len;
static ssize_t epbuf_read(struct file *fp, char __user *ubuf,
size_t count, loff_t *off)
{
size_t to_copy;
unsigned long not_copied;
if (*off >= data_len)
return 0; /* signal EOF */
to_copy = min(count, data_len - (size_t)*off);
not_copied = copy_to_user(ubuf, kbuf + *off, to_copy);
if (not_copied) {
pr_err("%s: copy_to_user failed, %lu bytes left uncopied\n",
DEV_NAME, not_copied);
return -EFAULT;
}
*off += to_copy;
return to_copy;
}
static ssize_t epbuf_write(struct file *fp, const char __user *ubuf,
size_t count, loff_t *off)
{
unsigned long not_copied;
size_t to_copy = min(count, (size_t)BUF_SIZE);
not_copied = copy_from_user(kbuf, ubuf, to_copy);
if (not_copied) {
pr_err("%s: copy_from_user failed, %lu bytes left uncopied\n",
DEV_NAME, not_copied);
return -EFAULT;
}
data_len = to_copy;
pr_info("%s: stored %zu bytes from user space\n", DEV_NAME, to_copy);
return to_copy;
}
static const struct file_operations epbuf_fops = {
.owner = THIS_MODULE,
.read = epbuf_read,
.write = epbuf_write,
};
static struct miscdevice epbuf_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEV_NAME,
.fops = &epbuf_fops,
};
static int __init epbuf_init(void)
{
int ret;
kbuf = kzalloc(BUF_SIZE, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
ret = misc_register(&epbuf_miscdev);
if (ret) {
kfree(kbuf);
return ret;
}
pr_info("%s: registered, /dev/%s ready\n", DEV_NAME, DEV_NAME);
return 0;
}
static void __exit epbuf_exit(void)
{
misc_deregister(&epbuf_miscdev);
kfree(kbuf);
pr_info("%s: unregistered\n", DEV_NAME);
}
module_init(epbuf_init);
module_exit(epbuf_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala example: copy_to_user/copy_from_user usage");
Try it out from the shell once loaded:
echo "hello kernel" | sudo tee /dev/epbuf_chardrv
sudo cat /dev/epbuf_chardrv
Real-World Use Cases
- Sensor drivers returning the latest reading to a monitoring application via
read() - Configuration drivers accepting settings written by a user-space daemon via
write() - Firmware-loading paths that move a firmware image from user space into a kernel buffer before sending it to hardware
Common Mistakes and Troubleshooting
| Mistake | Consequence | Fix |
|---|---|---|
| Ignoring the return value | Silent data corruption on partial copies | Always check for non-zero and return -EFAULT |
| Not bounding count against your buffer size | Kernel buffer overflow | Clamp with min() against your fixed buffer size |
| Using memcpy() instead | Kernel crash on invalid user pointers | Always use copy_to_user()/copy_from_user() |
| Forgetting to update *off in read() | Repeated reads never reach EOF | Advance the offset by the bytes actually copied |
Best Practices
- Always treat any non-zero return from these functions as a hard error and return
-EFAULT. - Clamp the requested
countagainst your kernel buffer’s real size before copying. - Keep the copy itself outside of any spinlock-protected critical section, since these calls can sleep on a page fault.
- Zero-initialize kernel buffers with
kzalloc()to avoid leaking stale kernel memory to user space.
Performance Considerations
Both functions include overhead for pointer validation, which is negligible for typical driver I/O sizes. For very high-throughput paths, consider batching data into fewer, larger transfers rather than many small ones, since each call carries fixed per-call overhead. If you find yourself calling copy_to_user() or copy_from_user() thousands of times per second with tiny payloads, redesigning your driver’s buffering strategy will usually help more than trying to optimize the copy calls themselves.
How This Fits Into the Bigger Picture
It helps to place copy_to_user() and copy_from_user() within the full lifecycle of a driver read or write call. When an application calls read() on your device node, the VFS layer locates your driver’s read method and invokes it with a user-space buffer pointer and a requested length. Your driver’s job is to fill an internal kernel buffer with the correct data — from hardware registers, a queue, or a cache — and then use copy_to_user() exactly once to hand that data back safely. The reverse happens for write(): user space hands you a pointer and length, and copy_from_user() is the only correct way to bring that data into kernel space before acting on it.
This separation is deliberate. The kernel never trusts a raw user-space pointer, and your driver code should follow the same discipline: validate lengths, clamp against your buffer size, and let these two functions handle the actual boundary crossing.
Security Considerations
These APIs exist specifically to prevent a malicious application from tricking your driver into reading or writing arbitrary kernel memory. Never bypass them with a direct pointer dereference, and never trust a count value from user space without clamping it against your actual buffer size — doing otherwise opens the door to buffer overflows and information leaks.
Key Takeaways
memcpy()is never safe across the kernel/user boundary — always usecopy_to_user()andcopy_from_user().- A return value of 0 means full success; anything else means partial failure that must be handled.
- Always clamp
countagainst your real buffer size before copying. - These calls can sleep, so never invoke them while holding a spinlock.
Conclusion
copy_to_user() and copy_from_user() are the foundation of every character driver that actually moves real data, rather than just pretending to. Once you’re comfortable checking their return values, clamping your buffer sizes, and keeping these calls out of spinlock-protected sections, you have everything you need to write correct and secure read and write methods for your own drivers. That completes this module of the free Linux device drivers course — from here, you’re ready to explore ioctl() and more advanced user-kernel communication mechanisms.
Frequently Asked Questions
Why can’t I just use memcpy() to copy data from a user buffer?
memcpy() cannot validate that a user-supplied pointer is actually mapped and accessible, and it doesn’t handle the architecture-specific details of crossing the kernel/user boundary safely.
What does a non-zero return value from copy_to_user() mean?
It means that many bytes could not be copied. Treat this as a failure and return -EFAULT from your driver method.
Can copy_to_user() or copy_from_user() be called while holding a spinlock?
No. These functions can trigger a page fault and sleep, which is not allowed while holding a spinlock. Use a mutex instead if locking is required around the copy.
How do I prevent a buffer overflow in my write() method?
Always clamp the incoming count against your kernel buffer’s actual size using min() before calling copy_from_user().
Do these functions work the same way on all CPU architectures?
The function signatures and behavior are consistent across architectures; the kernel handles the architecture-specific details internally, which is exactly why you should never replace them with a raw memcpy().
What error code should a driver return on a failed copy?
-EFAULT is the standard errno used to indicate a bad address during a user-kernel data copy.
Should I zero-initialize my kernel buffer before using it?
Yes. Using kzalloc() instead of kmalloc() avoids exposing uninitialized kernel memory to user space through a partial or malformed read.
This lecture is part of EmbeddedPathashala’s free Linux kernel development and device drivers course.
Explore More Free Courses
2 Comments