Bug 1375750 - SECCOMP support for libreswan
Summary: SECCOMP support for libreswan
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: libreswan
Version: 7.4
Hardware: All
OS: Linux
medium
low
Target Milestone: rc
: ---
Assignee: Paul Wouters
QA Contact: Ondrej Moriš
Mirek Jahoda
URL:
Whiteboard:
Keywords:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2016-09-13 22:24 UTC by Paul Wouters
Modified: 2019-04-21 09:36 UTC (History)
7 users (show)

(edit)
.SECCOMP can be now enabled in _libreswan_

As a Technology Preview, the `seccomp=enabled|tolerant|disabled` option has been added to the `ipsec.conf` configuration file, which makes it possible to use the Secure Computing mode (SECCOMP). This improves the syscall security by whitelisting all the system calls that *Libreswan* is allowed to execute. For more information, see the `ipsec.conf(5)` man page.
Clone Of:
(edit)
Last Closed: 2018-04-10 17:22:34 UTC


Attachments (Terms of Use)


External Trackers
Tracker ID Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2018:0932 None None None 2018-04-10 17:23 UTC
Red Hat Bugzilla 1544463 None NEW ipsec service does not work correctly when seccomp filtering is enabled 2019-04-21 09:35 UTC

Internal Trackers: 1544463

Description Paul Wouters 2016-09-13 22:24:12 UTC
Add support for seccomp in libreswan.

This is currently under development at upstream.

Comment 2 Ondrej Moriš 2016-10-05 14:33:17 UTC
Paul, could you be more specific about this RFE? How are you planning to use seccomp? Do you have any pointers to upstream information?

Comment 3 Paul Wouters 2016-10-05 17:23:04 UTC
We are using it to limit the number of syscalls that could be called by pluto or and the pluto helpers

See: people.redhat.com/pwouters/libreswan-3.19-seccomp.patch

Comment 4 Paul Wouters 2016-10-05 17:26:03 UTC
(note we still need to do some profiling so we can sort the filter and reduce the overhead)

Comment 5 Paul Wouters 2017-03-14 21:10:37 UTC
Moving to 7.5 as it seems there is still some issues with not having all syscalls whitelisted. I'd prefer to postpone this while upstream gains a bit more experience with the list of syscalls.

This feature is an option in the spec file for those who want to try it out, but disabled for the 7.4 build

Comment 9 Ondrej Moriš 2017-12-08 14:59:43 UTC
Paul, seccomp support on RHEL-7 seems not to be working correctly. Enabling or even tolerating setting caused odd service state "reloading (reload)". Moreover I think I am not supposed to see SECCOMP audit records if there are no problems, right? See more details below.

# cat /etc/ipsec.conf
version 2.0

config setup
 plutodebug="all"
 plutostderrlog="/var/log/pluto.log"
 protostack=netkey
 nat_traversal=yes
 virtual_private=
 oe=off
 seccomp=enabled

# rpm -q libreswan kernel
libreswan-3.22-2.el7.x86_64
kernel-3.10.0-799.el7.x86_64

# service ipsec restart
Redirecting to /bin/systemctl restart ipsec.service

# service ipsec status
Redirecting to /bin/systemctl status ipsec.service
● ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec
   Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled; vendor preset: disabled)
   Active: reloading (reload) since Fri 2017-12-08 09:49:20 EST; 1s ago
     Docs: man:ipsec(8)
           man:pluto(8)
           man:ipsec.conf(5)
  Process: 32234 ExecStopPost=/usr/sbin/ipsec --stopnflog (code=exited, status=0/SUCCESS)
  Process: 32233 ExecStopPost=/sbin/ip xfrm state flush (code=exited, status=0/SUCCESS)
  Process: 32231 ExecStopPost=/sbin/ip xfrm policy flush (code=exited, status=0/SUCCESS)
  Process: 32229 ExecStop=/usr/libexec/ipsec/whack --shutdown (code=exited, status=0/SUCCESS)
  Process: 32506 ExecStartPre=/usr/sbin/ipsec --checknflog (code=exited, status=0/SUCCESS)
  Process: 32504 ExecStartPre=/usr/sbin/ipsec --checknss (code=exited, status=0/SUCCESS)
  Process: 32242 ExecStartPre=/usr/libexec/ipsec/_stackmanager start (code=exited, status=0/SUCCESS)
  Process: 32241 ExecStartPre=/usr/libexec/ipsec/addconn --config /etc/ipsec.conf --checkconfig (code=exited, status=0/SUCCESS)
 Main PID: 32518 (pluto)
   Status: "Startup completed."
   CGroup: /system.slice/ipsec.service
           └─32547 addconn --ctlsocket /run/pluto//pluto.ctl --autoall
           ‣ 32518 [pluto]

Dec 08 09:49:20 systemd[1]: Starting Internet Key Exchange (IKE) Protocol Daemon ......
Dec 08 09:49:20 addconn[32241]: Warning: ignored obsolete keyword 'nat_traversal'
Dec 08 09:49:20 _stackmanager[32242]: Warning: ignored obsolete keyword 'nat_traversal'
Dec 08 09:49:20 _stackmanager[32242]: Warning: ignored obsolete keyword 'nat_traversal'
Dec 08 09:49:20 ipsec[32506]: Warning: ignored obsolete keyword 'nat_traversal'
Dec 08 09:49:20 ipsec[32506]: nflog ipsec capture disabled
Dec 08 09:49:20 systemd[1]: Started Internet Key Exchange (IKE) Protocol Daemon f...ec.
Dec 08 09:49:21 ipsec_starter[32547]: Warning: ignored obsolete keyword 'nat_traversal'
Hint: Some lines were ellipsized, use -l to show in full.

# ausearch -ts 09:49:20 -i -m SECCOMP
----
type=SECCOMP msg=audit(12/08/2017 09:49:21.785:522) : auid=unset uid=root gid=root ses=unset subj=system_u:system_r:ipsec_t:s0 pid=32518 comm=pluto sig=SIGSYS arch=x86_64 syscall=openat compat=0 ip=0x7f78d2f258d0 code=kill 

Eventually systemd watchdog kill it:

Dec 08 09:56:01 systemd[1]: ipsec.service: main process exited, code=killed, status=31/
Dec 08 09:56:01 systemd[1]: ipsec.service watchdog timeout (limit 3min 20s)!
Dec 08 09:55:42 systemd[1]: ipsec.service reload operation timed out. Stopping.

Comment 10 Paul Wouters 2017-12-08 16:01:42 UTC
It looks like we ended up using the syscall openat, that we did not have on our whitelist. So we need to add that syscall. I've launched a scratchbuild with that syscall added to the list. Can you re-run the test(s) and see if any other syscalls show up?

scratchbuild going now at: 

Task info: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14719049

Comment 11 Ondrej Moriš 2017-12-08 16:33:42 UTC
Got two more to whitelist now with 3.22-5:

1. This one shows during start:

type=SECCOMP msg=audit(12/08/2017 11:23:57.264:379) : auid=unset uid=root gid=root ses=unset subj=system_u:system_r:ipsec_t:s0 pid=11373 comm=pluto sig=SIGSYS arch=x86_64 syscall=getdents compat=0 ip=0x7fb93190dde5 code=kill

2. This one shows during stop:

type=SECCOMP msg=audit(12/08/2017 11:30:48.782:409) : auid=unset uid=root gid=root ses=unset subj=system_u:system_r:ipsec_t:s0 pid=12079 comm=pluto sig=SIGSYS arch=x86_64 syscall=sendto compat=0 ip=0x7fea91e48c5b code=kill 

Service is still in "reloading" state (and then timeouts again). 

BTW: I checked it once more with tolerant setting and I got "reloading" again but no SECCOMP audit event at all.

Comment 12 Paul Wouters 2017-12-11 17:54:43 UTC
I'll add getdents, but I'm confused about sendto, since that's been in the list from the start:

paul@thinkpad:~/libreswan (master *)$ git blame programs/pluto/pluto_seccomp.c |grep sendto
4a66a13120 (Paul Wouters      2016-10-10 19:06:08 -0400 101) 		rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0);

Maybe Paul Moore can shed some light on this?

Comment 13 Paul Moore 2017-12-11 18:29:16 UTC
(In reply to Paul Wouters from comment #12)
> I'll add getdents, but I'm confused about sendto, since that's been in the
> list from the start:
> 
> paul@thinkpad:~/libreswan (master *)$ git blame
> programs/pluto/pluto_seccomp.c |grep sendto
> 4a66a13120 (Paul Wouters      2016-10-10 19:06:08 -0400 101) 		rc |=
> seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0);

It looks like only the filter for "main" gets sendto() added to the filter, could this be the problem?

Comment 14 Ondrej Moriš 2018-01-04 11:11:46 UTC
Switching back to ASSIGNED since we cannot use libreswan with seccomp support at the moment (see Comments 9 and 11).

Comment 15 Ondrej Moriš 2018-01-09 14:12:10 UTC
Retested with libreswan-3.22-5.el7 and kernel-3.10.0-823.el7:

a) seccomp=disabled
   - ipsec service can be started, is running and can be stopped
   - seccomp test (ipsec whack --seccomp-crash) PASSED:

     003 Performing seccomp security test using getsid() syscall
     003 pluto: seccomp test syscall was not blocked
     003 OK: pluto seccomp was disabled and the rogue syscall was not blocked

b) seccomp=tolerant
   - ipsec service can be started, is running and can be stopped
   - seccomp test FAILED

     003 Performing seccomp security test using getsid() syscall
     003 pluto: seccomp test syscall was not blocked
     003 ERROR: pluto seccomp was tolerant but the rogue syscall was not blocked

     No SECCOMP event produced at all!

c) seccomp=enabled
   - ipsec service can be start, is running and can be stopped
   - seccomp test HANGED

     003 pluto is running with seccomp=enabled! pluto is expected to die!
     003 Performing seccomp security test using getsid() syscall
     ...<hang for 3 minutes>...
     
     Then exits with exit code 3. A single SECCOMP event can be observed:

     type=SECCOMP msg=audit(01/09/2018 08:45:47.908:18574) : auid=unset uid=root     
     gid=root ses=unset subj=system_u:system_r:ipsec_t:s0 pid=28479 comm=pluto 
     sig=SIGSYS arch=x86_64 syscall=getsid compat=0 ip=0x7f83fe9db647 code=kill 

     ipsec service restarted those 3 minutes:

     systemd[1]: ipsec.service watchdog timeout (limit 3min 20s)!
     systemd[1]: ipsec.service: main process exited, code=killed, status=31/SYS

     Therefore, it seems like it is working correctly. Paul, can you confirm 
     that this is expected behaviour?

All in all, both disabled and enabled seccomp setting is working at the moment, however - tolerant is not.

Comment 16 Paul Wouters 2018-01-09 17:15:08 UTC
It works as upstream :)

for the tolerant one:

     003 ERROR: pluto seccomp was tolerant but the rogue syscall was not blocked

I was going to ask Paul Moore about that.

I would change your test to not hang for 3 minutes but run the whack in the
background, sleep 1 second and check the SECCOMP in audit log. It is expected
pluto will be shot. Why the kernel would take 3 minutes, I don't know. Also, systemd watchdog should kick in sooner. What might be happening is that your whack command died but you are still waiting for something on the socket and your test framework stops that after 3 minutes? I thought the watchdog timer was set to 1 minute for systemd?

Ahh looks like default SD_WATCHDOGSEC is 200 seconds. One reason it is not shorter is that when people use XAUTH to type in their password, it blocks pluto and if they run "up" and then go find their hardware token, it would kill pluto. Once we make this password input not block pluto, we can put in a sane value like 30s

Note the tolerant setting was more a testing kind of thing. Clearly without knowing what didnt execute, you are in danger territory and run the risk of hitting a passert() soon afterwards.

Comment 17 Ondrej Moriš 2018-01-10 20:39:38 UTC
Thanks Paul. It is good to hear that. Based on the last two comments I am switching this bug back to ON_QA and I will proceed with automated verification.

Comment 18 Ondrej Moriš 2018-01-19 19:33:26 UTC
It seems that addconn wants to use clone syscall (56 on intel) when ipsec service is started:

----
time->Fri Jan 19 13:51:38 2018
type=SECCOMP msg=audit(1516387898.863:106): auid=4294967295 uid=0 gid=0 ses=4294967295 subj=system_u:system_r:unconfined_service_t:s0 pid=31422 comm="addconn" exe="/usr/libexec/ipsec/addconn" sig=31 arch=c00000b7 syscall=56 compat=0 ip=0xffff8028caa8 code=0x0

According to pluto_seccomp.c in 3.23rc4 clone syscall is allowed only for "main". It is worth mentioning that I see this only when executing test in out testing infrastructure (ie. without interactive terminal, with slightly different selinux context, ...) but it is still valid use case.

Shouldn't we whitelist clone event as well (not only for "main")?

Comment 19 Paul Wouters 2018-01-19 22:57:17 UTC
I've added clone() to the whitelist of addconn in programs/pluto/addconn.c

I've also double checked the addconn syscall white list. Since pluto forks an
addconn, everything in addconn has to be in the pluto list for "main".

That resulted in me adding prctl() and socketpair()

The /usr/sbin/ip: permission denied is still present :/

Comment 20 Ondrej Moriš 2018-01-28 21:01:32 UTC
While testing on non-intel architectures I realized we also need to whitelist socketcall syscall:

type=SECCOMP msg=audit(01/28/2018 21:37:14.256:169) : auid=unset uid=root gid=root ses=unset subj=system_u:system_r:unconfined_service_t:s0 pid=8021 comm=addconn sig=SIGSYS arch=ppc64 syscall=socketcall compat=0 ip=0x3fffb0b15ea8 code=kill

Comment 21 Paul Wouters 2018-01-29 03:05:19 UTC
added to upstream - we can backport

Comment 22 Ondrej Moriš 2018-01-29 06:42:35 UTC
Perfect! Can you create a scratch build? I'll check all architectures and we can ask Mark or Libor for exception / blocker in the meantime.

Comment 24 Ondrej Moriš 2018-02-06 09:23:02 UTC
Ad "Doc Text: Feature: A new option seccomp=yes enables syscall...". Shouldn't it be "...seccomp=enabled..."?

Comment 25 Paul Wouters 2018-02-06 16:38:37 UTC
yes, fixed :)

Comment 35 errata-xmlrpc 2018-04-10 17:22:34 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2018:0932


Note You need to log in before you can comment on or make changes to this bug.