User Space and Kernel Space
A modern operating system separates ordinary programs from the code that controls the machine. User space contains applications, shells, libraries, language runtimes, and system daemons. Kernel space contains the kernel's scheduler, virtual memory manager, filesystems, networking stack, security checks, and most device drivers.
The terms describe a protection boundary, not who uses a program. A root-owned daemon such as systemd still runs in user space. An unprivileged process can enter kernel mode through a system call, but it does not thereby become root or gain permission to execute arbitrary kernel code.
Hardware privilege and memory protection
CPUs provide privilege levels. Linux normally runs application instructions in an unprivileged user mode and kernel instructions in privileged kernel mode. On x86 these correspond mainly to rings 3 and 0; other architectures use different names and mechanisms. The distinction is enforced by the processor, not by a convention in C code.
User-mode code cannot execute privileged instructions, directly configure page tables, or
read arbitrary physical and kernel memory. If it tries to access an unmapped or forbidden
address, the CPU raises an exception. The kernel handles that exception, perhaps by
supplying a missing page, delivering SIGSEGV, or terminating the process.
Each process sees a virtual address space. Page tables translate its virtual addresses to
physical pages and attach permissions such as readable, writable, executable, and
user-accessible. Different processes can use the same virtual address for unrelated
physical memory. They can also deliberately share pages, for example through a shared
mmap() mapping.12
A process address space usually contains:
higher addresses
+---------------------------+
| kernel mappings | inaccessible in user mode
+---------------------------+
| stack and mapped regions | libraries, files, anonymous mappings
| heap |
| executable and data |
+---------------------------+
lower addresses
The exact layout, address widths, and placement of kernel mappings depend on the architecture and kernel configuration. Address-space layout randomization also moves many user mappings between executions. The diagram is a model, not a portable address map.
Physical RAM is not permanently divided into “user RAM” and “kernel RAM.” The kernel owns and manages all physical pages. At one moment a page may hold process memory; later the kernel may reclaim it for the page cache or another process. “Kernel space” more often means privileged execution and protected virtual addresses than a fixed partition of the DIMMs.1
Crossing the boundary
An application asks the kernel to perform privileged work through a system call. On Linux, system calls are the fundamental interface between applications and the kernel. They cover operations such as opening files, mapping memory, creating processes, sending network traffic, waiting for events, and changing process attributes.3
A typical path looks like this:
application code
|
| calls read() in libc
v
C library wrapper
|
| places syscall number and arguments according to the architecture ABI
| executes a syscall/trap instruction
v
kernel entry code
|
| validates pointers, file descriptor, credentials, and arguments
| performs or starts the requested operation
v
kernel exit code
|
| returns a result or error
v
C library wrapper sets errno when needed
|
v
application resumes in user mode
The processor changes privilege mode at a controlled entry point and switches to kernel-managed entry state. Linux performs bookkeeping for tracing, auditing, seccomp, signals, scheduling, and other pending work before returning to user mode.4
Applications normally call a C library wrapper rather than emit a system call instruction.
The wrapper handles the architecture ABI and converts the kernel's error convention into
-1 plus errno. A library function is not necessarily a one-to-one system call: it may
perform work entirely in user space, call several system calls, or select among kernel
interfaces.35
Some frequently requested information can be read without entering kernel mode. Linux
maps a small virtual shared object, the vDSO, into processes. The C library may use its
functions for operations such as reading the clock. Because no system call occurs, such a
call does not appear in strace.6
System calls are not the only way execution reaches the kernel:
- A hardware interrupt can arrive from a timer, network card, or other device.
- An exception can result from a page fault, invalid instruction, breakpoint, or arithmetic condition.
- The scheduler can preempt a task and run another one.
- A kernel thread can run kernel work without a corresponding user-mode program.
An interrupt can occur while the CPU is already executing either user or kernel code. A system call is synchronous and requested by the current thread; an external hardware interrupt is asynchronous to that thread.4
Processes, threads, and scheduling
A program is executable code and data.
A process is a running resource container with an address space, credentials, open file descriptors, signal dispositions, and one or more threads.
A thread is a schedulable execution stream. Threads in one process share most process resources but have separate register state and stacks.
Linux schedules tasks, including user threads and kernel threads, onto CPUs. A user thread
can accumulate both user CPU time and system CPU time: user time while its instructions
run in user mode, system time while the kernel works on its behalf. A blocking read()
may put the thread to sleep until data arrives, allowing the CPU to run something else.
The process has crossed into the kernel, but a CPU need not remain occupied for the
duration of the wait.
A context switch and a user/kernel mode switch are different events. A system call can enter and leave kernel mode while the same thread keeps the CPU. A context switch changes the running task and can happen while the kernel is handling a syscall, an interrupt, or a scheduler request.
Protection is finer than root versus non-root
Kernel mode and root privilege are different axes:
- Kernel code executes with hardware privilege and can access kernel memory.
- A UID 0 process normally executes ordinary instructions in user mode.
- On a system call, the kernel checks the calling thread's credentials and security policy before acting.
- Linux capabilities split many traditional root powers into narrower per-thread privileges, such as binding a low port or administering network interfaces.7
Even root must use kernel interfaces to open files, map memory, or configure devices. Root's credentials pass many policy checks, but they do not make application instructions execute in kernel mode. Conversely, kernel code handling a syscall runs in kernel mode while still applying the calling process's credentials and limits.
The boundary protects processes from one another as well as protecting the kernel. A program cannot ordinarily inspect another process's private mappings, overwrite the kernel's scheduler, or drive hardware directly. Bugs in kernel code are therefore more dangerous than ordinary process crashes: a driver or filesystem fault can corrupt shared kernel state or compromise the whole system.
Kernel interfaces visible as files
Linux exposes several kernel interfaces through file descriptors and virtual filesystems:
/procpresents process and system information backed by kernel data structures; tools such as ps turn that data into process listings./sysexposes devices, drivers, buses, and other kernel objects./devcontains device nodes whose file operations are implemented by drivers.- sockets, pipes, event descriptors, and many other kernel objects appear as file descriptors to a process.
These paths look like ordinary files so applications can use familiar operations such as
open(), read(), write(), mmap(), and ioctl(). The bytes are not necessarily stored
on disk. Reading /proc/meminfo, for example, asks procfs code in the kernel to generate a
view of current state.8
This does not mean every operating-system service belongs in the kernel. DNS resolution, login management, logging, desktop environments, package management, and service supervision normally run as user-space processes. Linux also supports user-space implementations for work often associated with kernels, such as FUSE filesystems. Moving code to user space limits the damage from a crash and permits ordinary development tools, though communication across the boundary can add overhead.
Isolation within user space
User space is not one shared privilege domain. Process credentials, page tables, file permissions, resource limits, capabilities, seccomp filters, and Linux Security Modules constrain individual processes.
Namespaces change the resources that a process can see. Linux has namespace types for mounts, process IDs, networking, IPC, hostnames, users, cgroups, and clocks. A container combines these views with cgroups and other controls; its processes still share the host kernel and invoke that kernel through system calls.9
This is the central difference between a container and a virtual machine. A virtual machine normally runs a guest kernel. A container supplies an isolated user-space view while retaining the host kernel. Namespace isolation does not create a second kernel space.
Why?
The user/kernel split gives Linux three useful properties:
- A process fault usually damages that process rather than the whole machine.
- The kernel can mediate access to memory, files, devices, networks, and other processes.
- Applications can depend on the user-space ABI instead of kernel-internal functions and data structures.
That last distinction matters to programmers. The supported application interface consists of system calls and other documented user-space ABIs. Kernel modules use internal kernel APIs, execute with kernel privilege, and must match the kernel they are built for. An application should not depend on kernel implementation details merely because both sides are written in C.
References
-
Linux kernel documentation, “Concepts overview” for memory management. ↩ ↩2
-
Linux man-pages,
syscalls(2). ↩ ↩2 -
Linux kernel documentation, “Entry/exit handling for exceptions, interrupts, syscalls and KVM”. ↩ ↩2
-
Linux man-pages,
syscall(2). ↩ -
Linux man-pages,
capabilities(7). ↩ -
Linux man-pages,
namespaces(7). ↩