[SOLVED] 'ipsec status' segfaults in LXD container

I have an Ubuntu Bionic container on LXD that runs strongSwan (the host is Bionic too). Symptoms:

  • I can start the ipsec service with systemctl
  • I can also use the ‘ipsec start|restart|stop’ commands
  • The VPN tunnel to a remote host is created.
  • However when I issue ‘ipsec status|statusall|listxxx|etc’ commands, I get a segfault:
    root@vpn1:~# ipsec statusall
    Segmentation fault

I tried the following:

  • I made sure that all kernel modules required by strongSwan are loaded and added to the container’s config (linux.kernel_modules = …)
  • Disabled AppArmor everywhere
  • Set the container to privileged
  • Launched a KVM VM using the same image (Ubuntu 18.04 LTS (Bionic Beaver) Daily Build [20180630]). It worked flawlessly.

Since it’s the same OS and strongSwan versions and the network config was similar, my only guess is it has something with LXD. I ran the ‘ipsec statusall’ with strace, here are the outputs:

Could you guys help solving this issue?

I found that ipsec is just a script calling ‘/usr/lib/ipsec/stroke’ for getting the status, and this process fails:

root@vpn1:~# strace /usr/lib/ipsec/stroke statusall
execve("/usr/lib/ipsec/stroke", ["/usr/lib/ipsec/stroke", "statusall"], 0x7fff5d0ae198 /* 14 vars */) = -1 EACCES (Permission denied)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=NULL} ---
+++ killed by SIGSEGV +++
Segmentation fault

I can see a permission denied, however the file is readable/executable by everyone and doesn’t have any acl set on it:

root@vpn1:~# ll /usr/lib/ipsec/stroke
-rwxr-xr-x 1 root root 22616 Mar 20 06:37 /usr/lib/ipsec/stroke*

root@vpn1:~# getfacl /usr/lib/ipsec/stroke
getfacl: Removing leading '/' from absolute path names
# file: usr/lib/ipsec/stroke
# owner: root
# group: root
user::rwx
group::r-x
other::r-x

One step closer but I still can’t find the root cause.

It was AppArmor! Even though I stopped the daemon, the modules were still loaded and in enforce mode:

root@vpn1:~# aa-status 
apparmor module is loaded.
18 profiles are loaded.
18 profiles are in enforce mode.
[...]
   /usr/lib/ipsec/charon
   /usr/lib/ipsec/lookip
   /usr/lib/ipsec/stroke
[...]

It started working after switching to complain mode:
root@vpn1:~# aa-complain /etc/apparmor.d/usr.lib.ipsec.

This is the log entry I see if I switch back to enforce mode:
Jul 7 04:53:32 lxd1 kernel: [ 4526.583617] audit: type=1400 audit(1530939212.389:68): apparmor="DENIED" operation="file_mmap" namespace="root//lxd-vpn1_<var-lib-lxd>" profile="/usr/lib/ipsec/stroke" name="/usr/lib/ipsec/stroke" pid=3372 comm="stroke" requested_mask="m" denied_mask="m" fsuid=100000 ouid=100000

I’ll dig into that profile.

I added /usr/lib/ipsec/stroke rm, to stroke’s AppArmor profile (line 26) and now it works well in enforced mode too. :smiley:

I’d like to add that packagers of strongswan now ship an updated AppArmor profile and this workaround is not required anymore.

Excellent, looks like we will need the same update to quassel as it’s running into the exact same denial (there’s another forum thread about that).

Hi community,

I am planning to test IPSEC inside an LXD container image to improve over a setup that currently uses VMs.

Given the thread above, is this currently something that works in 20.04 container images or would it need workarounds?

Thank you,
Gustavo