Gentoo Hardening: Part 2: Introduction to PaX and Grsecurity

Configuring PaX with Grsecurity

We've already briefly discussed PaX, but now it's time to describe it in detail. PaX provides the following security enhancements:

  • Non-executable memory: Sections that do not contain actual program code are marked as non-executable to prevent jumping to arbitrary location in memory and executing the code from there. Therefore, PaX ensures that program data is kept in a non-executable memory region from which we cannot execute code.
  • ASLR: PaX provides support for randomizing the address space of the program to prevent sections from being loaded to the same base address upon program/system restart.
  • Miscellaneous memory protection: PaX also provides other protections that are described in [5].

We've also mentioned that we need to use PaX-enabled kernel such as hardened-sources in order to use PaX. The hardened-sources kernel also supports Grsecurity, which is why we'll be using it here. First we need to install it onto the current system.

# emerge sys-kernel/hardened-sources

This will download and extract the kernel into /usr/src/ directory; the kernel will have the word "hardened" contained in the name, which is how we can differentiate between different kernels. To configure a hardened kernel, we should enter the kernel directory /usr/src/linux-3.10.1-hardened-r1/ and issue the "make menuconfig " command. Then we should go under Security Options – Grsecurity, where the following will be available. Note that some options are only available in amd64 architecture, while others are available on x86; we'll be looking only at the amd64 configuration options, but they should be pretty much the same on both architectures.

We must choose "Customize Configuration," which will present PaX-related settings to us, as shown below.

The PaX menu has the following options available (note that the description provided with each of the options presented below is taken from kernel's Help menu, which you can also see on the picture above). ** **

  • Enable various PaX features

    • PaX control

      • Support soft mode: Allows running PaX in soft mode, which doesn't enforce PaX features by default; PaX is enabled only on explicitly marked executables.
      • Use ELF program header marking: Enables adding PaX-specific header to ELF executable, which enables us to enable/disable PaX features on executable basis by using paxctl.
      • Use filesystem extended attributes marking: Similar option to the "Use ELF program header marking" except that per executable PaX features are controlled with setfattr, where the control flags are read from the user.pax.flags extended file attribute. Note that the filesystem used must support these extended attributes, so we should only use this option with supported filesystems.
      • MAC system integration [none, direct, hook]: Option for controlling per executable PaX features through mandatory access control (MAC) system. ** **
    • Non-executable page

      • Enforce non-executable pages: Memory pages are marked as non-executable, which prevents an attacker from loading a shellcode into memory and executing it; typical memory sections that need to be marked as non-executable are stack and heap, which need to be marked as non-executable if we want to prevent various kinds of attacks like stack or heap buffer overflows. If this option is disabled, then the memory block returned by malloc function will be readable as well as executable, which shouldn't be the case; the memory region returned by malloc should not be executable. There are some programs that rely on memory returned by malloc to be executable, like WINE, but we should learn to live without those programs (at least on hardened machine).

      • Paging based non-executable pages: Paging feature of the CPU that uses hardware non-executable bit support.

      • Emulate trampolines: Some programs use trampolines to execute instructions from non-executable memory pages. If we enable the non-executable pages, programs won't be able to use the trampolines anymore. Therefore, to still allow specific programs to use trampolines, we should enable this feature to emulate the trampolines but still have the protection provided by non-executable pages.

      • Restrict mprotect(): this option prevents programs from changing the non-executable memory pages into executable, changing read-only memory pages into writable, creating executable pages from anonymous memory, and making relro data pages writable again. We can also use chpax or paxctl to control this feature on a per executable basis.

        • Use legacy/compat protection demoting: When an application tries to allocate RWX memory, the kernel denies access by returning the proper error code to the application.
        • Allow ELF text relocations: The libraries that use position-independent code do not need to relocate their code, which the attacker can use to attack the system; this is why we shouldn't enable this option.
      • Enforce non-executable kernel pages: when we use this option, injecting code into kernel memory is harder, because the kernel enforces non-executable bit on kernel pages; this is a kernel-mode equivalent of PAGEEXEC and MPROTECT.

        • Return Address Instrumentation Method [bts, or]: Specify the method used to dereference pointers. The "bts" option is compatible with binary-only modules, but has a higher runtime overhead, while the "or" is incompatible with binary-only modules, but has lower runtime overhead. ** **
    • Address Space Layout Randomization

      • Address Space Layout Randomization: By enabling this option, we can randomize the following memory areas when the program is loaded: task's kernel and user stack, base address of executable and base address for mmap() function calls that creates a new mapping in the process's virtual address space.
      • Randomize kernel stack base: Randomizes the kernel stack of every task running in the kernel.
      • Randomize user stack base: Randomizes the user stack of every task running in the user-space.
      • Randomize mmap() base: Randomizes the base address for the mmap() function calls, which causes all dynamically loaded libraries to be loaded at random addresses, making it harder to guess the right address. ** **
  • Miscellaneous Hardening Features

    • Sanitize kernel stack: When enabled, this option deletes the kernel stack before returning from a system call, which reduces the information a kernel stack leak can reveal. If you decide to enable this option, keep in mind that the slowdown of the system will be about 1%.
    • Forcibly initialize local variables copied to userland: When enabled, this option zero-initializes some local variables that are copied to user space to prevent information leakage from the kernel. This option is similar to the previous option, but doesn't slow down the system as much.
    • Prevent invalid userland pointer dereference: When enabled, this option prevents dereferencing userland pointers where kernel pointers are expected, which can be useful in preventing exploitation due to the kernel bugs. Whenever a program calls into the kernel to do some action, the kernel needs to take the userland pointer and read data from it. Malicious software can exploit that to perform some actions in the kernel that should not be allowed; when this option is enabled, the kernel doesn't directly use the userland pointer.
    • Prevent various kernel object reference counter overflows: When enabled, this option prevents overflowing various kinds of object reference counters due to their abuse. Reference counters are used for counting objects, but an attacker can misuse them by incrementing them so much that they will reach the maximum number and wrap around, which might set the counter to zero or to a negative number. This can result in unexpected actions such as freeing the memory that's still being used.
    • Automatically constify eligible structures: When enabled, this option will automatically mark a class that contains only function pointers as being constant, which prevents overwriting this piece of memory (because it's marked as const). This prevents the attacks that try to overwrite function pointers to point to shellcode, which is executed when that function gets called.
    • Harden heap object copies between kernel and userland: When enabled, the kernel will enforce the size of heap objects when they are copied between user and kernel land.
    • Prevent various integer overflows in function size parameters: When enabled, the kernel will recompute expressions passed as function arguments with double precision and, if an overflow occurs, the event is logged and the process killed.
    • Generate some entropy during boot: when enabled, the kernel will extract some entropy from program state, which causes a minor slowdown of the system boot process.

Memory protections

  • Deny reading/writing to /dev/kmem, /dev/mem, and /dev/port: When enabled, we won't be able to use the /dev/kmem, /dev/mem, /dev/port, and /dev/cpu/*/msr, which means that an attacker won't be able to insert malicious code into the running kernel; the attacker won't even be able to open those devices if this option is enabled. But, he might still be able to modify the running kernel by using privileged I/O through ioperm/iopl.
  • Disable privileged I/O: When enabled, the ioperm/iopl calls will be disabled and will return an error, which will prevent an attacker from changing the running kernel by using those operations. If you use X server with your hardened kernel, this option should be disabled, otherwise the X server will fail to start with "xf86EnableIOPorts: failed to set IOPL for I/O (Operation not permitted)" failure message.
  • Disable unprivileged PERF_EVENTS usage by default: When enabled, the /proc/sys/kernel/perf_event_paranoid can be set to 3 through sysctl, which will prevent unprivileged use of PERF_EVENTS syscalls. - Insert random gaps between thread stacks: When enabled, a random gap will be put between thread stacks, which reduces the reliability of overwriting another thread's stack.
  • Harden ASLR against information leaks and entropy reduction: When enabled, the /proc/<pid>/maps and /proc/<pid>/stat will contain no information about the memory addresses used by the process <pid>. Additionally, the suid/sgid binary programs will have the argv/env strings limited to 512KB and stack limited to 8MB to prevent abuse. We need to enable this to harden the ASLR security a little bit more, so it can't be easily bypassed.
  • Deter exploit bruteforcing: Often programs start a new thread or fork a new child in order to accept a new connection. This allows an attacker to bruteforce the unknown part of the shellcode in order to gain code execution; this is possible because the target process is not killed, only the thread/child is killed. This option slows down bruteforcing attempts by delaying the parent process by 30 seconds on every fork when a child is killed by PaX or crashed due to an illegal instruction. When that happens, the administrator will have to manually restart the daemon to make it behave normally again.
  • Harden module auto-loading: When enabled, the module auto-loading will be limited to privileged users. This prevents loading vulnerable modules into the kernel by unprivileged users. We can also disable the auto-loading of modules altogether but, depending on the use, we might not want to do that; therefore this option is perfect for limiting access to auto-loading features.
  • Hide kernel symbols: When enabled, the information on loaded modules and displaying kernel symbols will be restricted to privileged users. This prevents unprivileged users from getting their hands on kernel information, such as variables, functions, and symbols.
  • Active kernel exploit response: When enabled, if a PaX alert is triggered because of suspicious activity in the kernel, the kernel will actively respond to the thread not only by terminating the process that caused the alert, but also by blocking the user that started the process to prevent further exploitation. If the user is root, then the kernel will panic the system; if it's a normal user, the alert will be logged, all user processes will be terminated and new processes (by the same user) will be permitted to start only after system restart.

Role-Based Access Control Options

  • Disable RBAC system: When enabled, the /dev/grsec device is removed from the kernel, which disables the RBAC system. If you want to use the RBAC system, you should leave this option disabled.
  • Hide kernel processes: When enabled, all kernel threads are hidden to all processes. We should enable this feature if we will use RBAC.
  • Maximum tries before password lockout: Specifies the maximum number of times a user can re-enter the password before being blocked for a certain period of time. This effectively prevents bruteforcing the password.
  • Time to wait after max password tries, in seconds: Specifies the time the user must wait after entering the password incorrectly a predefined number of times.

Filesystem Protections

  • Proc restrictions: When enabled, the security of the /proc filesystem will be hardened.

    • Restrict /proc to user only: When enabled, the non-root users will only be able to see their own processes.
    • Allow special group: When enabled, a chosen group will be able to see all processes and network information, while the kernel and symbol information may still remain invisible (depends on other options).
    • Additional restrictions: When enabled, the /proc filesystem will be further protected by restricting normal users from seeing device and slabinfo information.
  • Linking restrictions: When enabled, the users will only be able to follow symlinks owned by themselves, but not other users in world-writable +t directories, such as /tmp. A sysctl option linking_restrictions is created.

  • Kernel-enforced SymlinksIfOwnerMatch: When enabled, a secure replacement for Apache's SymlinksIfOwnerMatch option will be used for the specified group. A sysctl option enforce_symlinksifowner is created.

  • FIFO restrictions: When enabled, each user will only be able to write to a FIFO he owns (in a world-writable +t directories such as /tmp). A sysctl option fifo_restrictions is created.

  • Sysfs/debugfs restriction: When enabled, the sysfs as well as debugfs will only be accessible by root. This lowers the possibility of an attacker exploiting those filesystems, whose purpose is to provide br access to hardware and debug information. This option doesn't go well with desktop system, because it leaks certain things. For example, if we want to start a wicd-client program, we'll get this error message "OSError: [Errno 13] Permission denied: '/sys/class/net/'" and the wicd-client won't be able to start under normal user; we can nevertheless run it as root. This option also breaks pulseaudio and battery widgets, which won't be able to get access to the /sys filesystem, which is why the pulseaudio on a hardened system might not work. Don't enable this option if you're on a desktop system.

  • Runtime read-only mount protection: When enabled, the filesystem will be protected so that no writable mounts are allowed, read-only mounts cannot be remounted as read-write, and write operations are disabled for block devices. This option is mainly useful for embedded devices. A sysctl option romount_protect is created.

  • Eliminate stat/notify-based device sidechannels: When enabled, the timing analysis on devices by using stat or inotify/dnotify/fanotify will be disabled for unprivileged users.

  • Chroot jail restrictions: When enabled, we can make breaking out of chrooted jail much more difficult. Various options can be enabled that will make processes inside jail more restrictive.

    • Deny mounts: Processes inside jail won't be able to mount filesystems.
    • Deny double-chroots: Processes inside jail won't be able to chroot again outside the chroot, which is one of the methods used for breaking out of chroot jail. A sysctl option chroot_deny_chroot is created.
    • Deny pivot_root in chroot: Processes inside jail won't be able to use the pivot_root() function, which can be used to break out of chroot by changing root filesystem. A sysctl option chroot_deny_pivot is created.
    • Enforce chdir("/") on all chroots: When enabled, the current working directory will be changed to the root directory of the chroot when chrooted applications are used. A sysctl option chroot_enforce_chdir is created.
    • Deny (f)chmod +s: Processes inside jail won't be able to chmod/fcmod files to change suid/sgid bits, which is just another method of breaking out of chroot. A sysctl option chroot_deny_chmod is created.
    • Deny fchdir out of chroot: When enabled, another attack method of breaking out of chroot environment will be prevented: the fchdiring to a file descriptor of the chrooting process that points to a directory outside the filesystem. A sysctl option chroot_deny_fchdir is created.
    • Deny mknod: Processes inside jail won't be allowed to use mknod, which an attacker can use to create the same device that already exists and steal or delete data from hard drive. A sysctl option chroot_deny_mknod is created.
    • Deny shmat() out of chroot: Processes inside jail won't be able to attach to shared memory segments that were created outside chroot. A sysctl option chroot_deny_shmat is created.
    • Deny access to abstract AF_UNIX sockets out of chroot: Processes inside jail won't be able to connect to sockets that were bound outside of chroot. A sysctl option chroot_deny_unix is created.
    • Protect outside processes: Processes inside jail won't be able to kill and view and processes outside chroot or send signals with fcntl, ptrace, capget, getpgid, setpgid, getsid. A sysctl option chroot_findtask is created.
    • Restrict priority changes: Processes inside jail won't be able to raise the priority of the processes in chroot. A sysctl option chroot_restrict_nice is created.
    • Deny sysctl writes: When enabled, a user in chroot won't be able to write to sysctl entries by sysctl or /proc. A sysctl option chroot_deny_sysctl is created.
    • Capability restrictions: When enabled, certain capabilities of the processes in chroot will be disabled. A sysctl option chroot_caps is created.
    • Exempt initrd tasks from restrictions: When enabled, tasks created prior to init will be excluded from chroot restrictions, which disables privileged operations of Plymouth's in chroot.

Kernel Auditing

  • Single group for auditing: This option can be used when we want to log only certain users on the system and not the whole system; we can specify only the group we want to monitor. A sysctl option audit_group is created.
  • Exec logging: When enabled, all execve and thus exec calls will be logged. This option is useful when the system is used as a server and we would like to keep track of users. A sysctl option exec_logging is created. Note that this option will produce a lot of logs on an active system.
  • Resource logging: When enabled, all requests for resources that try to allocate more than the maximum limit will be logged. A sysctl option resource_logging is created.
  • Log execs within chroot: When enabled, all executions inside chroot jail will be logged to syslog. A sysctl option chroot_execlog is created.
  • Ptrace logging: when enabled, all attempts to attack a process via ptrace will be logged. A sysctl option audit_ptrace is created.
  • Chdir logging: When enabled, all chdir calls are logged. A sysctl option audit_chdir is created.
  • (Un)Mount logging: When enabled, all mounts/unmounts will be logged. A sysctl option audit_mount is created.
  • Signal logging: When enabled, various signals will be logged, which might be triggered because of a possible exploit attempt. A syslog option signal_logging is created.
  • Fork failure logging: When enabled, all failed fork attempts will be logged, which can detect a fork bomb. A sysctl option forkfail_logging is created.
  • Time change logging: When enabled, any changes to the system time are logged. A sysctl option timechange_logging is created.
  • /proc/<pid>/ipaddr support: When enabled, a new entry /proc/<pid>/ipaddr will be created, containing the address of the person using the task.
  • Denied RWX mmap/mprotect logging: When enabled, the mmap and mprotect calls will be logged when being blocked by PaX. A syslog option rwxmap_logging is created.
  • ELF text relocations logging: When enabled, the text relocations in certain binary/library will be logged. We can use this to detect the programs or libraries that need text relocations in order to get rid of them. A sysctl option audit_textrel is created.

Executable Protections

  • Dmesg(8) restriction: When enabled, the non-root users won't be able to use the dmesg command to view the kernel logs, which might contain kernel addresses that the attacker could use for exploitation. A sysctl option dmesg is created.

  • Deter ptrace-based process snooping: when enabled, a non-root user won't be able to attach to an arbitrary process and monitor it by using ptrace. A sysctl option harden_ptrace is created.

  • Require read access to ptrace sensitive binaries: When enabled, a non-root users won't be able to monitor unreadable binaries by using ptrace. A syslog option ptrace_readexec is created.

  • Enforce consistent multithreaded privileges: When using multi-threaded application, a change from root uid to non-root uid will be propagated through all the threads, not just the current one. A sysctl option consistent_setxid is created.

  • Trusted path execution (TPE): This option restricts the execution of files based on their path, which makes privilege escalation exploiting harder; if an attacker can upload a binary into an untrusted path on the server, he won't be able to execute it. When using this option on a desktop system, it's best to set the "Invert GID option." By using TPE, file execution is more restricted, which might also break emerge from install certain packages sometimes, but it's nevertheless a useful security option. If we merely enabled the TPE without enabling the options below, only a selected group will be able to execute files in root-owned directories writable only by root. A sysctl option tpe is created.

    • Partially restrict all non-root users: If enabled, all non-root users will be able to execute files in root-owned directories writable by root and directories owned by the user, which are not group- or world-writable. A sysctl option tpe_restrict_all is created.
    • Invert GID option: This option specifies that users in not in the chosen group will only be able to execute files in-root owned directories writable only by root (this option restricts users from executing files in user-owned directories that are not group- or world-writable). Additionally, the selected group will not have this option enabled, which is useful if we want to apply TPE to most users on the system except the ones specified on chosen group. A sysctl option tpe_incert is created.
    • GID for TPE-untrusted users/GID for TPE-trusted users: Note that this option makes changes based on previously selected options. Whenever this option specifies "GID for TPE-untrusted users," it actually specifies the group that will have TPE enabled; the group will be marked as untrusted and the execution permissions of users belonging to that group will be limited. When the option is "GID for TPE-trusted users," it specifies a group whose users will be able to execute files in a user-owned directory which is not group- or world-writable. A sysctl option tpe_gid is created.

Network Protections

  • Larger entropy pools: When enabled, the entropy used by Linux will double.

  • TCP/UDP blackhole and LAST_ACK DoS prevention: When enabled, neither TCP RST nor ICMP destination-unreachable packets will be sent as a response for packets received with no listening process. This feature can be very useful if we want to reduce the visibility against scanners such as nmap. Two sysctl options ip_blackhole and lastack_retries will be created.

  • Disable TCP simultaneous connect

  • Socket restrictions

    • Deny any sockets to group: Specifies a group that won't be able to connect to other hosts or run server applications. A sysctl option socket_all is created.
    • Deny client sockets to group: Specifies a group that won't be able to connect to other hosts, but will be able to run server applications. A sysctl option socket_client is created.
    • Deny server sockets to group: Specifies a group that won't be able to run server applications. A sysctl option socket_server is created.

Sysctl Support

  • Sysctl support: When enabled, we will be able to change the grsecurity options without recompiling the kernel. We can change values by changing the values in /proc/sys/kernel/grsecurity.

    • Extra sysctl support for distro makers: When enabled, additional sysctl options are created that can be used to manipulate processes running as root. In order to use this option, grsec_lock needs to be enabled after boot.
    • Turn on features by default: If enabled, all sysctl features are enabled by default.

Logging Options

  • Add source IP address to SELinux AVC log messages: When enabled, the source IP address of the remote machine will be added to log messages.
  • Seconds in between log messages: Specifies the number of seconds between grsecurity log messages.
  • Number of messages in a burst: Specifies the maximum number of messages allowed within the flood time interval.

After we've enabled all the options that we want to use, we must save the kernel configuration and build the kernel by executing the command below:

# make && make modules && make modules_install

After that, we should copy our newly built kernel to /boot directory and change the grub.conf to boot from newly built kernel. We can copy the kernel to /boot partition with the command below:

# cp arch/x86_64/boot/bzImage /boot/kernel-hardened

The grub.conf should then look like this:

title=Gentoo
root (hd0,0)
kernel /boot/kernel-hardened root=/dev/sda3

If something goes wrong or doesn't work after the reboot, we should start the rsyslog daemon and look into the /var/log/syslog file for grsec entries, which should clearly state the reason for problems. We should start with the kernel that gives us the least privilege and then slowly add permissions as needed.

# /etc/init.d/rsyslog start
# tail -f /var/log/syslog

References:

[1] Hardened Gentoo http://www.gentoo.org/proj/en/hardened/. [2] Security-Enhanced Linux http://en.wikipedia.org/wiki/Security-Enhanced_Linux:Security-Enhanced_Linux. [3] RSBAC http://en.wikipedia.org/wiki/RSBAC. [4] Hardened/Toolchain https://wiki.gentoo.org/wiki/Hardened/Toolchain#RELRO. [5] Hardened/PaX Quickstart https://wiki.gentoo.org/wiki/Project:Hardened/PaX_Quickstart. [6] checksec.sh http://www.trapkit.de/tools/checksec.html. [7] KERNHEAP http://subreption.com/products/kernheap/. [8] Advanced Portage Features http://www.gentoo.org/doc/en/handbook/handbook-amd64.xml?part=3&chap=6. [9] Elfix http://dev.gentoo.org/~blueness/elfix/. [10] Avfs: An On-Access Anti-Virus File System http://www.fsl.cs.sunysb.edu/docs/avfs-security04/. [11] Eicar Download, http://www.eicar.org/85-0-Download.html. [12] Gentoo Security Handbook, http://www.gentoo.org/doc/en/security/security-handbook.xml.

Comments