DEV Community

Marek „Netbe” Lampart
Marek „Netbe” Lampart

Posted on

Linux Security Is More Than Root: Syscalls, Capabilities, Namespaces, eBPF and AI-Assisted Privilege Escalation

Linux Security Is More Than Root: Syscalls, Capabilities, Namespaces, eBPF and AI-Assisted Privilege Escalation

For a long time, Linux security was explained with a simple model:

user → process → root

That model is still useful.

It is also incomplete.

A modern Linux application can interact with the kernel through syscalls, operate inside multiple namespaces, hold individual capabilities instead of full root privileges, be restricted by seccomp, pass through LSM controls, interact with eBPF infrastructure, and run inside a container that only looks isolated from the outside.

This changes how developers should think about Linux security.

The interesting question is no longer simply:

"Is this process running as root?"

A better question is:

"What exactly is this process allowed to ask the kernel to do?"

That distinction matters for containers, CI/CD runners, Kubernetes workloads, security agents, build systems and almost every service running on a Linux server.

1. The Linux security boundary starts at the syscall

Applications do not directly manipulate kernel internals.

They request services from the kernel through system calls.

A simplified application flow looks like this:

Application
     |
     v
libc / runtime
     |
     v
syscall
     |
     v
Linux kernel
     |
     v
Resource / device / filesystem / network
Enter fullscreen mode Exit fullscreen mode

Consider a program opening a file:

int fd = open("/etc/passwd", O_RDONLY);
Enter fullscreen mode Exit fullscreen mode

The application is not simply "reading a file."

It is asking the kernel to perform an operation.

The kernel then evaluates the request against several security mechanisms.

Depending on the operation, those mechanisms can include:

  • traditional Unix permissions,
  • capabilities,
  • namespaces,
  • seccomp,
  • Linux Security Modules,
  • filesystem restrictions,
  • credentials,
  • cgroups,
  • kernel configuration.

This is why a compromised application does not automatically receive unlimited kernel access.

There are multiple security boundaries between the process and the resource.

2. Root is not the same thing as unlimited authority

The traditional Unix model treats UID 0 as extremely powerful.

Modern Linux breaks many privileged operations into individual capabilities.

You can inspect the current process capabilities with:

capsh --print
Enter fullscreen mode Exit fullscreen mode

You can also inspect the process directly:

grep Cap /proc/$$/status
Enter fullscreen mode Exit fullscreen mode

Capabilities include permissions such as:

CAP_NET_ADMIN
CAP_SYS_ADMIN
CAP_SYS_PTRACE
CAP_DAC_OVERRIDE
CAP_SYS_MODULE
CAP_BPF
Enter fullscreen mode Exit fullscreen mode

This creates a much more granular security model.

For example, a service may need permission to manipulate networking without needing permission to load kernel modules.

That leads to an important container-security principle:

Don't give a workload root privileges
when it only needs one specific capability.
Enter fullscreen mode Exit fullscreen mode

Docker provides a practical example:

docker run --cap-drop=ALL myapp
Enter fullscreen mode Exit fullscreen mode

Capabilities can then be added individually if the application genuinely requires them.

For example:

docker run \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  myapp
Enter fullscreen mode Exit fullscreen mode

The exact capabilities required depend on the application.

The important part is the model:

start with zero and add only what is necessary.

3. CAP_SYS_ADMIN is a special kind of problem

One capability deserves particular attention:

CAP_SYS_ADMIN
Enter fullscreen mode Exit fullscreen mode

It covers a very broad collection of privileged operations.

This is why security documentation sometimes jokingly refers to it as the "new root."

That description is simplified, but it captures the practical problem: granting a container broad administrative capabilities can destroy much of the isolation you thought you had.

Before adding:

--cap-add=SYS_ADMIN
Enter fullscreen mode Exit fullscreen mode

to a production container, determine exactly which operation requires it.

Sometimes the correct solution is not another capability.

It is redesigning the workload.

4. Namespaces change what a process can see

Linux namespaces provide isolation by changing the resources visible to a process.

A process can have separate views of:

  • processes,
  • networking,
  • mounts,
  • users,
  • IPC,
  • hostnames,
  • cgroups.

You can inspect the namespaces of the current shell:

ls -l /proc/$$/ns/
Enter fullscreen mode Exit fullscreen mode

Typical output includes:

cgroup
ipc
mnt
net
pid
user
uts
Enter fullscreen mode Exit fullscreen mode

A container is therefore not simply a "small virtual machine."

It is a collection of Linux isolation mechanisms.

This distinction matters.

A VM normally has a stronger hardware virtualization boundary.

A container shares the host kernel.

If a vulnerability crosses a kernel boundary, container isolation may not save you.

5. User namespaces are particularly interesting

User namespaces allow a process to have different user and group identities inside and outside the namespace.

For example:

Inside namespace:
UID 0

Outside namespace:
UID 100000
Enter fullscreen mode Exit fullscreen mode

The process can therefore appear to be root inside its namespace without being UID 0 on the host.

This is a powerful security mechanism.

It is also an important source of complexity.

Security bugs involving namespace transitions, kernel interfaces and privilege checks have historically produced serious container-escape vulnerabilities.

For developers, the takeaway is straightforward:

container isolation depends heavily on the host kernel.

Updating the container image while ignoring the host kernel is not a complete security strategy.

6. Seccomp can reduce the kernel attack surface

Linux provides another useful mechanism:

seccomp.

Instead of allowing a process to invoke every syscall available on the system, seccomp can restrict the available syscall interface.

You can check whether the current process is running under seccomp:

grep Seccomp /proc/$$/status
Enter fullscreen mode Exit fullscreen mode

A restricted process might have a much smaller effective interface:

Application
     |
     v
Allowed syscalls
     |
     v
Linux kernel
Enter fullscreen mode Exit fullscreen mode

This matters because a vulnerability in an application is not automatically equivalent to unrestricted kernel access.

If an attacker compromises the process, seccomp can prevent or limit some follow-up actions.

In container environments, seccomp should therefore be treated as a practical defense layer rather than an optional curiosity.

7. LSM adds another security layer

Linux Security Modules provide another control point.

Common implementations include:

  • AppArmor
  • SELinux
  • Smack

You can check active LSMs with:

cat /sys/kernel/security/lsm
Enter fullscreen mode Exit fullscreen mode

A typical system might return something similar to:

capability,landlock,yama,apparmor,bpf
Enter fullscreen mode Exit fullscreen mode

The exact result depends on the distribution and kernel configuration.

The important point is architectural.

Linux security is not one giant permission check.

It is a stack of controls.

Application
    |
    +-- Unix permissions
    |
    +-- Capabilities
    |
    +-- Namespaces
    |
    +-- Seccomp
    |
    +-- LSM
    |
    +-- cgroups
    |
    v
Linux kernel
Enter fullscreen mode Exit fullscreen mode

Breaking through one layer does not necessarily remove the others.

8. eBPF changes the trust model

eBPF is one of the most interesting additions to modern Linux.

It allows programs to run inside the kernel under controlled conditions.

Developers use eBPF for:

  • observability,
  • networking,
  • tracing,
  • performance analysis,
  • security monitoring,
  • runtime enforcement.

You can inspect BPF programs with:

bpftool prog show
Enter fullscreen mode Exit fullscreen mode

Maps:

bpftool map show
Enter fullscreen mode Exit fullscreen mode

And links:

bpftool link show
Enter fullscreen mode Exit fullscreen mode

This is incredibly powerful.

It also means that security teams need to understand who is allowed to interact with BPF.

A process with excessive BPF-related privileges can gain access to capabilities that ordinary application code should never have.

Modern Linux security therefore includes another question:

Who can load, attach or manipulate BPF programs?

That question did not exist in the same form in older Linux security models.

9. Containers do not eliminate the kernel attack surface

Suppose an application is running inside Docker:

Internet
   |
   v
Web application
   |
   v
Container
   |
   v
Host kernel
Enter fullscreen mode Exit fullscreen mode

The application is isolated from many host resources.

But the kernel remains shared.

That means a kernel vulnerability can potentially become a container-escape vulnerability.

The same principle applies to Kubernetes.

A pod is not a replacement for kernel security.

Developers should therefore keep two update cycles in mind:

Application dependencies
        +
Container base image
        +
Host kernel
        +
Container runtime
Enter fullscreen mode Exit fullscreen mode

Updating only the first two does not remove vulnerabilities in the latter components.

10. no_new_privs is an underrated defense

Linux provides a useful process-level control called:

no_new_privs
Enter fullscreen mode Exit fullscreen mode

It prevents a process from gaining additional privileges through mechanisms such as set-user-ID programs or file capabilities.

You can check it with:

grep NoNewPrivs /proc/$$/status
Enter fullscreen mode Exit fullscreen mode

For containers, this can be combined with capability reduction:

docker run \
  --cap-drop=ALL \
  --security-opt=no-new-privileges:true \
  myapp
Enter fullscreen mode Exit fullscreen mode

For many workloads, this is a cheap additional security boundary.

It does not magically make an application secure.

It reduces the number of ways a compromised process can increase its privileges.

That is exactly what a defense layer should do.

11. Privilege escalation is increasingly automated

There is another change developers should not ignore.

Privilege escalation is no longer limited to humans manually running enumeration tools.

AI systems can already automate parts of the workflow:

Initial access
      |
      v
Environment enumeration
      |
      v
Identify privileges
      |
      v
Find misconfiguration
      |
      v
Select attack path
      |
      v
Attempt escalation
Enter fullscreen mode Exit fullscreen mode

The important part is not the word "AI."

Automation already existed.

AI can reduce the amount of manual reasoning required to connect information gathered from a compromised environment.

A developer should therefore assume that an attacker can rapidly enumerate:

id
whoami
sudo -l
uname -a
ss -tulpn
findmnt
getcap -r / 2>/dev/null
find / -perm -4000 -type f 2>/dev/null
Enter fullscreen mode Exit fullscreen mode

These commands expose useful information about the security boundary.

The goal is not to hide them.

The goal is to ensure that their output does not reveal an easy path to privilege escalation.

12. A practical Linux privilege-escalation audit

For a development or staging host, start with identity:

id
whoami
groups
Enter fullscreen mode Exit fullscreen mode

Check sudo permissions:

sudo -l
Enter fullscreen mode Exit fullscreen mode

Inspect capabilities:

getcap -r / 2>/dev/null
Enter fullscreen mode Exit fullscreen mode

Find SUID binaries:

find / -perm -4000 -type f 2>/dev/null
Enter fullscreen mode Exit fullscreen mode

Find SGID binaries:

find / -perm -2000 -type f 2>/dev/null
Enter fullscreen mode Exit fullscreen mode

Inspect network services:

ss -tulpn
Enter fullscreen mode Exit fullscreen mode

Inspect mounted filesystems:

findmnt
Enter fullscreen mode Exit fullscreen mode

Inspect scheduled tasks and timers:

systemctl list-timers --all
Enter fullscreen mode Exit fullscreen mode

Then examine:

  • writable system directories,
  • writable service files,
  • dangerous environment variables,
  • exposed Docker sockets,
  • Kubernetes credentials,
  • cloud metadata access,
  • SSH keys,
  • CI/CD secrets,
  • service accounts,
  • unnecessary capabilities.

This is defensive enumeration.

The same information can obviously be useful to an attacker.

That is precisely why developers should know what their systems expose.

13. Docker hardening example

A baseline container could look like this:

docker run \
  --cap-drop=ALL \
  --security-opt=no-new-privileges:true \
  --read-only \
  myapp
Enter fullscreen mode Exit fullscreen mode

This does three useful things:

  1. Drops Linux capabilities.
  2. Prevents privilege acquisition through certain mechanisms.
  3. Makes the container filesystem read-only.

The application may need exceptions.

For example, a service requiring a writable temporary directory may need:

--tmpfs /tmp
Enter fullscreen mode Exit fullscreen mode

Security should therefore be driven by application requirements rather than a random collection of flags copied from a blog post.

14. The developer's security checklist

Before deploying a Linux service, ask:

Process

  • Does it need root?
  • Can it run as an unprivileged UID?
  • Does it require Linux capabilities?

Syscalls

  • Can seccomp reduce the available syscall surface?
  • Does the container runtime provide an appropriate profile?

Filesystem

  • Does the application really need write access?
  • Which directories must be writable?
  • Are secrets exposed through the filesystem?

Network

  • Which ports are actually required?
  • Can outbound traffic be restricted?
  • Does the application need raw socket access?

Containers

  • Are unnecessary capabilities removed?
  • Is no-new-privileges enabled?
  • Is the root filesystem read-only?
  • Is the container runtime current?

Kernel

  • Is the host kernel patched?
  • Are dangerous interfaces restricted?
  • Are BPF permissions controlled?

Monitoring

  • Are privilege changes logged?
  • Are unexpected processes detected?
  • Are container escapes and namespace changes monitored?

15. The real Linux security model

The most useful mental model is not:

user → root
Enter fullscreen mode Exit fullscreen mode

It is:

Application
    |
    v
Process credentials
    |
    +---- Unix permissions
    |
    +---- Capabilities
    |
    +---- Namespaces
    |
    +---- Seccomp
    |
    +---- LSM
    |
    +---- cgroups
    |
    +---- eBPF controls
    |
    v
Linux kernel
    |
    v
Hardware / network / storage
Enter fullscreen mode Exit fullscreen mode

Every additional boundary increases the work required to turn an application compromise into a host compromise.

That is the real purpose of defense in depth.

Not perfect security.

More boundaries.

More verification.

More opportunities to stop the attack before it reaches the next layer.

Conclusion

Linux security has moved far beyond the old "root versus non-root" model.

Syscalls define the interface.

Capabilities divide privileged operations.

Namespaces isolate resources.

Seccomp limits syscall access.

LSMs enforce additional security policies.

eBPF introduces powerful kernel-level instrumentation and another security boundary to control.

Containers combine several of these mechanisms, but still share the host kernel.

And increasingly automated attack tooling means that weak configurations can be discovered faster than before.

For developers, the practical rule is simple:

Do not ask only what user your application runs as. Ask what the application can make the kernel do.

That is where the real Linux security boundary lives.

Further reading

Top comments (0)