Protect against ptrace of processes: kernel.yama.ptrace_scope

Protect against the usage of Ptrace

Hardening the kernel with kernel.yama.ptrace_scope

Ptrace is a great troubleshooting tool for developers to determine how a process functions. It can be used to find programming flaws, like memory leakage. On the other hand, the tool also be used by people with malicious intent. For example to debug a process as a non-privileged user and find the contents of application memory.

Yama

Linux has the ability to include Linux Security Modules, to provide additional features with the means of a module. Yama does Discretionary Access Control of some kernel related functions, like defining if process tracing (prace) is allowed.

kernel.yama.ptrace_scope

The parameter kernel.yama.ptrace_scope helps system administrators to select what processes can be debugged with ptrace.

We can determine the active value with sysctl or using the pseudo file system /proc and find the related key.

$ sysctl kernel.yama.ptrace_scope
kernel.yama.ptrace_scope = 1

or

$ cat /proc/sys/kernel/yama/ptrace_scope
1

For this particular key there are four valid options: 0-3

  • kernel.yama.ptrace_scope = 0: all processes can be debugged, as long as they have same uid. This is the classical way of how ptracing worked.
  • kernel.yama.ptrace_scope = 1: only a parent process can be debugged.
  • kernel.yama.ptrace_scope = 2: Only admin can use ptrace, as it required CAP_SYS_PTRACE capability.
  • kernel.yama.ptrace_scope = 3: No processes may be traced with ptrace. Once set, a reboot is needed to enable ptracing again.

Using Ptrace – Advice

Screenshot showing the sandbox options of Google, with Yama LSM being enforced.

Yama LSM enforcing enabled

Servers

If your system is running in the DMZ and processes high sensitive data, there is usually no reason to allow ptrace at all. Best is to disable it completely (kernel.yama.ptrace_scope = 3).

For servers in general you might want to apply rule, or choose a slightly less restrictive value (2 or 1).

Desktops

On desktop systems where you are the only user, can have a less restricted option (2, 1 or even disabled).

The Yama LSM is also used in Google Chrome, as can been seen in the related screenshot.

If you want to dive deeper into the details of this LSM, have a look at Yama Linux Security Module.

facebooktwittergoogle_plusredditpinterestlinkedinmail

Auditing systemd: solving failed units with systemctl

Auditing systemd

Solving failed units with systemctl

Systemd is an alternative service manager to the more traditional init system. To ensure the system is healthy, failed units should be investigated on a regular basis. Sooner or later a unit might fail and showing up the systemctl listing. In this article we have a look at how to solve it.

Why do services fail?

During the start of the system, enabled services are started and queued to be executed. Most processes will start correctly and systemd logs the related status in the journal. However, in some cases a service might enter a “failed state”, as a result of another command not finishing properly.

[root@localhost ~]# systemctl
 UNIT                                     LOAD   ACTIVE SUB       DESCRIPTION
 -.mount                                  loaded active mounted   /
 boot.mount                               loaded active mounted   /boot
 dev-hugepages.mount                      loaded active mounted   Huge Pages File System
 ● dev-mqueue.mount                       loaded failed failed    POSIX Message Queue File System
 run-user-0.mount                         loaded active mounted   /run/user/0
 sys-kernel-config.mount                  loaded active mounted   Configuration File System
 sys-kernel-debug.mount                   loaded active mounted   Debug File System
 tmp.mount                                loaded active mounted   Temporary Directory

Services usually fail because of a missing dependency (e.g. a file or mount point), missing configuration, or incorrect permissions. In this example we see that the dev-mqueue unit with type mount fails. As the type is a mount, the reason is most likely because mounting a particular partition failed.

By using the systemctl status command we can see the details of the dev-mqueue.mount unit:

[root@localhost ~]# systemctl status dev-mqueue.mount
● dev-mqueue.mount - POSIX Message Queue File System
   Loaded: loaded (/usr/lib/systemd/system/dev-mqueue.mount; static)
   Active: failed (Result: exit-code) since Sun 2014-11-23 17:53:10 CET; 4min 12s ago
    Where: /dev/mqueue
     What: mqueue
     Docs: man:mq_overview(7)
           http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
  Process: 446 ExecMount=/bin/mount -n mqueue /dev/mqueue -t mqueue (code=exited, status=32)

Nov 23 17:53:10 localhost.localdomain systemd[1]: dev-mqueue.mount mount process exited, code=exited status=32
Nov 23 17:53:10 localhost.localdomain systemd[1]: Failed to mount POSIX Message Queue File System.
Nov 23 17:53:10 localhost.localdomain systemd[1]: Unit dev-mqueue.mount entered failed state.

This shows the related command which was executed. We see the unit failed on exit-code as it was not the expected value of 0 (actually it is 32). Manually running the command shows the device /dev/mqueue is missing.

Similar to this service, IPMI fails on our virtual machine. As there is no /dev/ipmi* device, the service can’t start and fails:

[root@localhost ~]# systemctl status ipmievd.service
 ? ipmievd.service - Ipmievd Daemon
 Loaded: loaded (/usr/lib/systemd/system/ipmievd.service; enabled)
 Active: failed (Result: exit-code) since Sun 2014-11-23 16:08:48 CET; 1h 36min ago
 Process: 550 ExecStart=/usr/sbin/ipmievd $IPMIEVD_OPTIONS (code=exited, status=1/FAILURE)
Nov 23 16:08:47 localhost.localdomain ipmievd[550]: Could not open device at /dev/ipmi0 or /dev/ipmi/0 or /dev/ipmidev/0: No such file or directory
 Nov 23 16:08:47 localhost.localdomain ipmievd[550]: Could not open device at /dev/ipmi0 or /dev/ipmi/0 or /dev/ipmidev/0: No such file or directory
 Nov 23 16:08:47 localhost.localdomain ipmievd[550]: ipmievd: using pidfile /var/run/ipmievd.pid0
 Nov 23 16:08:47 localhost.localdomain ipmievd[550]: Could not open device at /dev/ipmi0 or /dev/ipmi/0 or /dev/ipmidev/0: No such file or directory
 Nov 23 16:08:47 localhost.localdomain ipmievd[550]: Unable to open interface
 Nov 23 16:08:48 localhost.localdomain systemd[1]: ipmievd.service: control process exited, code=exited status=1
 Nov 23 16:08:48 localhost.localdomain systemd[1]: Failed to start Ipmievd Daemon.
 Nov 23 16:08:48 localhost.localdomain systemd[1]: Unit ipmievd.service entered failed state.
 Nov 23 16:08:48 localhost.localdomain systemd[1]: ipmievd.service failed.

Clearing failed units

You can manually clear out failed units with the systemctl reset-failed command. This can be done for all units, or a single one.

Services which are no longer needed, are better to be stopped and disabled.

systemctl stop rngd.service
systemctl disable rngd.service

That’s all!

facebooktwittergoogle_plusredditpinterestlinkedinmail

Filtering ARP traffic with Linux arptables

Filtering ARP traffic with Linux arptables

Most Linux system administrators will be familiar with iptables on Linux. Less known is the arptables utility, which controls filtering arp packets.

Installation

The arptables utility is easy to set-up, as the main functionality is already implemented in the Linux kernel. Just install the arptables package on your favorite Linux distribution.

Red Hat / CentOS / Fedora

yum install arptables

Debian / Ubuntu

apt-get install arptables

Configuration example

To show the effect of filtering traffic, we will show an example by filtering router traffic and blocking it. This way we won’t be able to connect to the internet.

With the arp command we can query the current list of known ARP addresses.

root@ubuntu:/data# arp
 Address                  HWtype  HWaddress           Flags Mask            Iface
 System.cisofy.com        ether   00:a7:22:23:d1:f3   C                     eth0
 Router.cisofy.com        ether   d8:d7:21:22:5a:8d   C                     eth0

Arptables can block traffic by filtering out the IP. So let’s query the arp list again, now in numeric format.

root@ubuntu:/data# arp -n
 Address                  HWtype  HWaddress           Flags Mask            Iface
 192.168.1.20             ether   00:a7:22:23:d1:f3   C                     eth0
 192.168.1.1              ether   d8:d7:21:22:5a:f4   C                     eth0

Time to block the router (192.168.1.1):

root@ubuntu:/data# arptables -A INPUT -s 192.168.1.1 -j DROP

So we dropped traffic to this IP adress, right? Let’s try!

root@ubuntu:/data# ping 192.168.1.1
 PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
 64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.645 ms
 64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.370 ms
 ^C
 --- 192.168.1.1 ping statistics ---
 2 packets transmitted, 2 received, 0% packet loss, time 1000ms
 rtt min/avg/max/mdev = 0.370/0.507/0.645/0.139 ms

Well, that didn’t work like intended. We dropped ARP related traffic to the IP address, but not on IP level. This is also visible in the arp -n list:

root@ubuntu:/data# arp -n
 Address                  HWtype  HWaddress           Flags Mask            Iface
 192.168.1.20             ether   00:a7:22:23:d1:f3   C                     eth0
 192.168.1.1              ether   d8:d7:21:22:5a:f4   C                     eth0

So to make this work, we simply have to flush the ARP cache. We delete the related ARP entry:

root@ubuntu:/data# arp -d 192.168.1.1
root@ubuntu:/data# arp -n
 Address                  HWtype  HWaddress           Flags Mask            Iface
 192.168.1.20             ether   00:a7:22:23:d1:f3   C                     eth0
 192.168.1.1                      (incomplete)                              eth0

The arp utility will show an incomplete entry. It knows that recently some traffic passed by, but the MAC address is unknown.

Let’s ping again:

root@ubuntu:/data# ping 192.168.1.1
 PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
 From 192.168.1.21 icmp_seq=1 Destination Host Unreachable
 From 192.168.1.21 icmp_seq=2 Destination Host Unreachable

That looks better!

Specific traffic filtering

Back to our original mission: only allow our router to exchange ARP packets.

root@ubuntu:/data# Block ARP traffic from all machines (default: DENY)
arptables -P INPUT DROP

root@ubuntu:/data# Allow router (fixed ARP)
arptables -A INPUT --source-mac d8:d7:21:22:5a:f4 -j ACCEPT

All ARP packets are blocked now. Each system which will transmitting traffic will end up as an (incomplete) entry.

Enable all ARP traffic

If we want to allow traffic again:

root@ubuntu:/data# arptables -P INPUT ACCEPT
root@ubuntu:/data# arptables --flush

Flushing the full ARP cache can be done with ip utility:

root@ubuntu:/data# ip -s neighbour flush all

Conclusion

Arptables is a very powerful utility to filter traffic and avoid an unexpected router taking over our connectivity. However, keep in mind that connectivity is not fully blocked. Only ARP traffic is blocked (layer 2/3 on the OSI model). If someone is able to manually add an entry to the ARP table, traffic is able to flow again.

facebooktwittergoogle_plusredditpinterestlinkedinmail
« Older Entries