Reinforcing NetBSD from within: understanding PaX mechanisms like ASLR and W^X, managing per-binary security flags with paxctl, and applying sysctl settings and server security best practices.

In episode 14 we secured communication with TLS and certificates. Now we go deeper — into the system itself. In this episode we'll reinforce NetBSD from within: security features and PaX — understanding PaX mechanisms like ASLR and W^X, managing per-binary security flags with paxctl, and applying sysctl settings and server security best practices.
Firewalls and TLS protect from the outside; PaX protects from within. If a program is successfully compromised — for example through a buffer overflow — PaX is the last layer that makes the attack fail. NetBSD has carried this tradition for a long time, and understanding it is an important part of becoming a mature NetBSD administrator.
PaX is a set of hardening techniques that make exploitation far more difficult. There are two core mechanisms:
| Mechanism | How It Works |
|---|---|
| ASLR | Randomizes memory addresses (stack, heap, libraries) each time a process runs — attackers don't know where to place or find code |
| W^X | Memory pages cannot be simultaneously Writeable and EXecutable — injected code can't be written and then executed |
With ASLR, return-to-libc and ROP attacks become far harder because addresses are always changing. With W^X, pages that are executable can't be written — so injecting code simply won't work.
Check the global PaX settings with sysctl -a | grep pax:
sysctl -a | grep paxproc.pax.flags = 0x0
paxtype = 0x0
security.pax.aslr.enabled = 1
security.pax.mprotect.enabled = 1A value of 1 means ASLR and mprotect (part of W^X) are globally active. This is the safe default on modern NetBSD.
Not every program plays well with all PaX protections. Sometimes a binary — for example a Java VM or an emulator — needs an exception. NetBSD provides paxctl to manage flags per binary.
paxctl /usr/pkg/bin/javaPaX flags on /usr/pkg/bin/java (default = enabled):
X: noexec-protected (enabled)
S: segvguard-protected (enabled)
A: aslr-protected (enabled)
M: mprotect-enabled (enabled)
E: emutramp-enabled (enabled)Each letter represents one protection: A for ASLR, M for mprotect, S for segvguard, X for noexec, E for emutramp.
If a binary has trouble with ASLR (for example random crashes), disable the ASLR protection:
paxctl -A /usr/pkg/bin/problematicpaxctl -v /usr/pkg/bin/problematicA quick explanation of the options:
| Option | Effect |
|---|---|
-A | Disables ASLR for this binary |
-a | Enables ASLR (the default value) |
-M | Disables mprotect |
-s | Shows the status of flags |
Warning
Don't disable PaX protections without a strong reason and testing. These protections are the last line of defense if a program is exploited. Better to find the root cause — like a wrong build flag — than to weaken security.
Here are the sysctl settings relevant to security:
sysctl securitysecurity.models.extensions.securelevel = 0
security.pax.aslr.enabled = 1
security.pax.mprotect.enabled = 1NetBSD has the securelevel concept — security levels that restrict operations while the system runs. The higher the level, the stricter:
| Level | Restrictions |
|---|---|
| 0 | Normal (default) |
| 1 | Secure: immutable file flags active, /dev/mem restricted |
| 2 | Stricter: /dev/mem read-only, raw disks restricted |
Raise the level permanently via rc.conf:
sysctl_security_models_extensions_securelevel=1sysctl -w security.models.extensions.securelevel=1Warning
Securelevel cannot be lowered without a reboot. Start at level 1 and test your services before going higher — some admin operations (like changing flags on important files) will be refused at higher levels.
sysctl -w net.inet.ip.forwarding=0
sysctl -w net.inet.tcp.rfc1948=1net.inet.ip.forwarding: 0 -> 0
net.inet.tcp.rfc1948: 0 -> 1rfc1948 randomizes the initial sequence number — making connection prediction harder. forwarding=0 means the system doesn't forward packets (not a router) — unless you actually want to be a router.
NetBSD also has veriexec — a system that checks the integrity of executable files against a checksum database. The tool for managing it is nbgc (NetBSD signed manifest). It's optional but very powerful for high-security environments:
veriexec -z /etc/signaturesVeriexec signatures database generatedWith veriexec active, changes to system binaries will be detected and prevented. Its implementation is complex — make this an advanced project, not your first security step.
| Practice | Details |
|---|---|
| Minimal install | Install only the packages you need |
| Regular patching | Schedule base system and pkgsrc updates |
| Firewall active | npf with default deny (episode 12) |
| Locked-down SSH | Key only, no root (episode 13) |
| PaX active | Leave the defaults; use paxctl only for special cases |
| Securelevel as needed | Test before raising the level |
| Tested backup and restore | If attacked, recover fast (episode 11) |
In this episode 15, you've reinforced NetBSD from within: understanding PaX mechanisms like ASLR and W^X, managing per-binary security flags with paxctl, applying sysctl settings and securelevel, and getting to know veriexec and server security best practices.
Key takeaways:
paxctl — don't disable them without reason and testing.sysctl security shows the kernel security settings; raise securelevel gradually and test.net.inet.tcp.rfc1948=1 randomizes the ISN — enable it.In the next episode, episode 16, we'll conquer the protocol of the future: IPv6 and advanced networking — autoconfiguration with SLAAC, DHCPv6, 6to4/6in4 tunneling, IPv6 firewall with npf, and advanced routing concepts. See you in episode 16!