From b3b2639c26ec3d6e2d23f40ecc951ff16ce0a082 Mon Sep 17 00:00:00 2001 From: Tobias Heider Date: Tue, 19 Apr 2022 19:10:46 +0200 Subject: [PATCH] Add apparmor support to further harden the priviledge seperation on Linux in a similar way pledge() is used on OpenBSD. The apparmor config contains profiles for the different iked processes (parent,ikev2,ca,control). Each process switches to their respective policy with aa_change_profile() before calling chroot() and setuid() to drop priviledges. --- CMakeLists.txt | 3 ++ contrib/iked.apparmor | 86 +++++++++++++++++++++++++++++++++++++++++++ iked/CMakeLists.txt | 18 +++++++-- iked/proc.c | 26 +++++++++++++ 4 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 contrib/iked.apparmor diff --git a/CMakeLists.txt b/CMakeLists.txt index d53c415f..c0effa44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -356,6 +356,9 @@ endif() if(HAVE_VROUTE OR HAVE_VROUTE_NETLINK) add_definitions(-DHAVE_VROUTE) endif() +if(WITH_APPARMOR) + add_definitions(-DWITH_APPARMOR) +endif() if(ASAN) message("Using ASAN") diff --git a/contrib/iked.apparmor b/contrib/iked.apparmor new file mode 100644 index 00000000..754858e7 --- /dev/null +++ b/contrib/iked.apparmor @@ -0,0 +1,86 @@ +# Last Modified: Thu Apr 14 17:48:19 2022 +abi , + +include + +profile iked /usr/sbin/iked { + include + + capability kill, + + # address/route configuration + capability net_admin, + network netlink dgram, + + # config file + include + /etc/iked.conf r, + /etc/iked/** r, + + # switch profile + owner @{PROC}/@{tid}/mounts r, + owner @{PROC}/@{tid}/attr/current w, + change_profile -> iked//ca, + change_profile -> iked//control, + change_profile -> iked//ikev2, + + signal (send) peer=iked//ca, + signal (send) peer=iked//control, + signal (send) peer=iked//ikev2, + signal (send) peer=iked//resolvectl, + + owner /run/iked.sock w, + network key raw, + + /usr/bin/resolvectl cx -> resolvectl, + profile resolvectl { + include + include + + signal (receive) peer=iked, + + /usr/bin/resolvectl r, + } + + profile ca { + include + + # privsep + capability setuid, + capability setgid, + capability sys_chroot, + signal (receive) peer=iked, + + # certs/keys + /etc/iked/** r, + } + + profile control { + include + + # privsep + capability setuid, + capability setgid, + capability sys_chroot, + signal (receive) peer=iked, + + # ikectl control sock + network unix raw, + } + + profile ikev2 { + include + + # privsep + capability setuid, + capability setgid, + capability sys_chroot, + signal (receive) peer=iked, + + # IKEv2 + network inet dgram, + network inet6 dgram, + # PFKEY + network key raw, + } +} diff --git a/iked/CMakeLists.txt b/iked/CMakeLists.txt index 7ae404ae..af8cfc6e 100644 --- a/iked/CMakeLists.txt +++ b/iked/CMakeLists.txt @@ -117,9 +117,16 @@ else() PRIVATE util event crypto ssl compat ) endif() -target_link_libraries(iked - PRIVATE util event crypto ssl compat iked-shared -) + +if(WITH_APPARMOR) + target_link_libraries(iked + PRIVATE util event crypto ssl compat iked-shared apparmor + ) +else() + target_link_libraries(iked + PRIVATE util event crypto ssl compat iked-shared + ) +endif() add_custom_command( OUTPUT parse.c @@ -150,6 +157,11 @@ install(FILES ${CMAKE_SOURCE_DIR}/iked.conf ) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/iked.conf.5 DESTINATION ${CMAKE_INSTALL_MANDIR}/man5/) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/iked.8 DESTINATION ${CMAKE_INSTALL_MANDIR}/man8/) +if(WITH_APPARMOR) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/iked.apparmor + DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/apparmor.d/ + RENAME usr.sbin.iked) +endif() install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/iked/ca) install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/iked/certs) install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/iked/crls) diff --git a/iked/proc.c b/iked/proc.c index 1e7c9ef5..922ae2c7 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -22,6 +22,10 @@ #include #include +#ifdef WITH_APPARMOR +#include +#endif + #include #include #include @@ -388,6 +392,28 @@ proc_run(struct privsep *ps, struct privsep_proc *p, fatalx(__func__); } +#ifdef WITH_APPARMOR + switch(p->p_id) { + case PROC_IKEV2: + if (aa_change_profile("iked//ikev2") == -1) + log_warnx("warning: aa_change_profile" + "(\"iked//ikev2\") failed"); + break; + case PROC_CONTROL: + if (aa_change_profile("iked//control") == -1) + log_warnx("warning: aa_change_profile" + "(\"iked//control\") failed"); + break; + case PROC_CERT: + if (aa_change_profile("iked//ca") == -1) + log_warnx("warning: aa_change_profile" + "(\"iked//ca\") failed"); + break; + default: + break; + } +#endif + /* Change root directory */ if (p->p_chroot != NULL) root = p->p_chroot;