Java exception when using cap_net_bind_service+ep with Logstash 5.x

I require Logstash to listen on TCP and UDP port 514. To do this, I use setcap to allow java to bind to this low port number. After doing this (and rerunning ldconfig), Java throws an exception.

logstash: Sending Logstash logs to /var/log/logstash which is now configured via log4j2.properties.
logstash: null:-2:in `getOpenFileDescriptorCount': java.lang.InternalError: 
errno: 13 error: Unable to open directory /proc/self/fd
logstash: from ProcessMonitor.java:37:in `<init>'
logstash: from ProcessMonitor.java:82:in `detect'
logstash: from RubyProcessReport.java:27:in `generate'
logstash: from RubyProcessReport$INVOKER$s$0$0$generate.gen:-1:in `call' 
logstash: from CachingCallSite.java:306:in `cacheAndCall'
logstash: from CachingCallSite.java:136:in `call'
logstash: from CallNoArgNode.java:60:in `interpret'
logstash: from LocalAsgnNode.java:123:in `interpret'
logstash: from NewlineNode.java:105:in `interpret'
logstash: from BlockNode.java:71:in `interpret'
logstash: from ASTInterpreter.java:74:in `INTERPRET_METHOD'
logstash: from InterpretedMethod.java:139:in `call'

Logstash version: 5.0.0-rc1-1 (installed from RPM)
OS: Oracle Linux 7.2 running kernel 3.8.13-118.13.2.el7uek.x86_64
Java version: Oracle JRE 1.8.0_111-b14

This doesn't appear to be an issue with Logstash itself, but it looks like it will effect any Logstash users that wish to bind to privileged ports. After using setcap on the java binary, I can see that it totally changes the permissions under Logstash's /proc entry from being owned by Logstash to being owned by root instead, which explains the error I'm seeing. One possible fix is to stop Logstash from calling "getOpenFileDescriptorCount"

Regards,
Nick

As a temporary workaround, you can add also CAP_DAC_READ_SEARCH capability, to allow reading /proc/self/fd regardless of permissions.
Surely this is not a viable definitive solution for security concerns, but it works in the meantime.
Regards,
federico

Thanks for your suggestion Federico. In the end, I used iptables to forward the traffic to the desired port. This allows me to get the desired outcome without giving java unnecessary permissions.

how you did the port forwarding. I use centos 7 with following command,
firewall-cmd --permanent --add-forward-port=port=514:proto=udp:toport=5514

But it's not working. Any Idea why is that??

Hi Bopa,

I'm afraid I have little experience with firewall-cmd. I'm using iptables (which I'm configuring using puppet)

This works for me:
sudo iptables -t nat -A PREROUTING -p tcp --dport 514 -j REDIRECT --to-port 5514

For forwall-cmd, have you enabled masquerading? As suggested in https://docs.fedoraproject.org/en-US/Fedora/19/html/Security_Guide/sec-Configure_Port_Forwarding-CLI.html

firewall-cmd --zone=external --add-masquerade
firewall-cmd --permanent --zone=external --add-forward-port=port=514:proto=tcp:toport=5514

Cheers,
Nick

1 Like

Will it work for udp as well?

Yes, works for UDP as well as it does for TCP. Just replace the "tcp" with "udp" in your rules.

Cheers,
Nick

1 Like