Project

General

Profile

Actions

Bug #1672

closed

Suricata Creates RWX Pages

Added by Shawn Webb over 8 years ago. Updated over 8 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
Affected Versions:
Effort:
Difficulty:
Label:

Description

This bug may be due to a shared library that Suricata brings in. During Shmoocon, I talked with Victor about this a little bit. He advised me to send a bug report, even if it's with a shared library.

When using the Emerging Threats rulesets, Suricata will create RWX pages, which cause Suricata to crash on HardenedBSD.

You can reproduce this by:
1) installing HardenedBSD
2) installing suricata: pkg install suricata
3) downloading the Emerging Threats rulesets to /usr/local/etc/suricata/rules directory
4) turning off NOEXEC: sysctl hardening.pax.pageexec.status=0
5) enabling suricata in /etc/rc.conf
6) starting suricata: service suricata start
7) looking at the memory mappings for suricata: (as root) procstat -v `pgrep suricata`

Attached is the output of that procstat command. You'll notice that the rwx pages are per-thread stacks, likely created by the RTLD on behalf of shared objects that request it in the .GNU_STACK section.


Files

suricata_rwx.log (11.1 KB) suricata_rwx.log Shawn Webb, 01/17/2016 10:00 AM
2016-01-19-rtld_noexec.patch (1.96 KB) 2016-01-19-rtld_noexec.patch Shawn Webb, 01/19/2016 10:40 PM
2016-01-19-suricata_procstat.txt (11 KB) 2016-01-19-suricata_procstat.txt Shawn Webb, 01/19/2016 10:42 PM
Actions #1

Updated by Victor Julien over 8 years ago

Looks like on Linux this map can be produced by: pmap $(pidof suricata)

A quick glance didn't show any rwx's.

Actions #2

Updated by Shawn Webb over 8 years ago

FreeBSD's RTLD will request on behalf of a shared object executable stack pages if that shared object has a .GNU_STACK section that requests it.

https://github.com/HardenedBSD/hardenedBSD/blob/hardened/current/master/libexec/rtld-elf/amd64/rtld_machdep.h#L80 <- default stack RWX on amd64
https://github.com/HardenedBSD/hardenedBSD/blob/hardened/current/master/libexec/rtld-elf/rtld.c#L246 <- integrating with the default stack RWX on amd64
https://github.com/HardenedBSD/hardenedBSD/blob/hardened/current/master/libexec/rtld-elf/rtld.c#L1336 <- very interesting line of code that forces RWX stack
https://github.com/HardenedBSD/hardenedBSD/blob/hardened/current/master/libexec/rtld-elf/rtld.c#L1371 <- GNU_STACK process header of a shared object can pull in RWX stack

I'll be researching this more on my side. I've already toyed with a hack around making the RTLD not allow an RWX stack on amd64: https://github.com/HardenedBSD/hardenedBSD-playground/commit/ee8313df956335bda85322ee6318bcbb1da49917. I've gotten tons of spurious machine reboots with that hack, though, so it's definitely not ready for prime time.

My next task is to go through all shared objects Suricata pulls in and look at their GNU_STACK section. Does Suricata use dlopen() at all? Or are all shared objects that are pulled in done at program load time? If Suricata uses dlopen, could you give me a list of shared objects that Suricata may load?

Actions #3

Updated by Shawn Webb over 8 years ago

The threading library in FreeBSD (libthr) is another place that can create executable stacks. This is driven by the RTLD.

https://github.com/HardenedBSD/hardenedBSD/blob/hardened/current/master/lib/libthr/thread/thr_stack.c#L134-L291

Actions #4

Updated by Victor Julien over 8 years ago

No, Suricata does not (yet) use dlopen.

Actions #5

Updated by Shawn Webb over 8 years ago

I've come up with a patch (which has been attached) to HardenedBSD's RTLD that fixes the problem. Long explanation from the git commit to an experimental HardenedBSD repo is below. In short, this is a problem with FreeBSD, not with Suricata. This bug report can be closed.

=== Begin log message ===
libthr calls into the RTLD to check whether the per-thread stacks it
creates should be executable. The RTLD makes that decision based on
whether shared objects have 1) a GNU_STACK process header; and 2) if
the GNU_STACK process header has the execute bit set. This change
fixes a bug wherein the RTLD defaults to setting the execute bit,
regardless of whether the shared object even contains a GNU_STACK
process header, thus forcing per-stack threads to be executable.

This research was done when my interest was piqued seeing Suricata
create RWX stack pages, even though none of its dependencies had a
GNU_STACK process header at all. With this commit (and a couple
others), Suricata does not need a secadm rule. PAGEEXEC and MPROTECT
can be fully enabled. === End log message ===

Actions #6

Updated by Shawn Webb over 8 years ago

Attached is new procstat output showing no RWX pages in Suricata now.

Actions #7

Updated by Victor Julien over 8 years ago

  • Status changed from New to Closed

Nice work Shawn!

Actions

Also available in: Atom PDF