collectd problems with grsecurity/PaX

I recompiled collectd some days ago, to get the latest version : 4.9.1.
When I tried to restart it, I was greeted with a nice error message:

root# /etc/init.d/collectd start
Starting statistics collection and monitoring daemon: collectd
lt_dlopen (/opt/collectd/lib/collectd/ failed: file not found
Unable to load plugin netlink.
root# ls -l /opt/collectd/lib/collectd/
-rwxr-xr-x 1 root root 26K 2010-03-30 23:43 /opt/collectd/lib/collectd/

*gasp*, so what’s wrong?

Well, I had to run strace to find out:

root# strace -fq /etc/init.d/collectd start >/var/tmp/strace.log 2>&1

Here’s the interesting part (unnecessary noise removed):

$ ...
[pid 29239] lstat64("/opt/collectd/lib/collectd/", {st_mode=S_IFREG|0755, st_size=26082, ...}) = 0
[pid 29239] open("/opt/collectd/lib/collectd/", O_RDONLY) = 4
[pid 29239] read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`\25\0\0004\0\0\0"..., 512) = 512
[pid 29239] mmap2(NULL, 24836, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x527d4000
[pid 29239] mmap2(0x527d9000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x4) = 0x527d9000
[pid 29239] close(4) = 0
[pid 29239] mprotect(0x527d4000, 20480, PROT_READ|PROT_WRITE) = -1 EACCES (Permission denied)
[pid 29239] munmap(0x527d4000, 24836) = 0
[pid 29239] socket(PF_FILE, 0x80002 /* SOCK_??? */, 0) = 4
[pid 29239] write(2, "lt_dlopen (/opt/collectd/lib/collectd/ failed: file not found", 73) = 73

It turns out it fails because of the PROT_WRITE flag of mprotect, which my grsecurity/PaX configuration denies. The error message that follows this error is extremely misleading, though…
netlink is the only plugin (on my configuration at least) that wants to use this flag. The proper way of fixing this situation should be to dig into the code, and see if we can remove the necessity of this flag.
But for now I just want a working configuration! So, I just asked PaX to allow this kind of thing for the collectd binary.

root# paxctl -cm /opt/collectd/sbin/collectd
file /opt/collectd/sbin/collectd had a PT_GNU_STACK program header, converted
root# /etc/init.d/collectd start
Starting statistics collection and monitoring daemon: collectd.

Phew, it works.