]> granicus.if.org Git - psmisc/commitdiff
pstree: add apparmor support
authorGeorgia Garcia <georgia.garcia@canonical.com>
Thu, 9 Sep 2021 18:30:40 +0000 (18:30 +0000)
committerGeorgia Garcia <georgia.garcia@canonical.com>
Mon, 18 Oct 2021 21:43:56 +0000 (21:43 +0000)
While the current fallback method might obtain the correct AppArmor
context by checking /proc/self/attr/current, it is not guaranteed that
this value will be the context attributed by AppArmor. The current
interface being used upstream is /proc/self/attr/apparmor/current, and
that can be obtained by using the AppArmor library functions.

In order to avoid link time dependencies, we are loading the apparmor
library dynamically, just like is currently done by SELinux.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
configure.ac
src/pstree.c

index 182a0dfd0d80dd455c6f754b98803618ccb1e314..ecc0c02414bbd7356856382f5d3f8726ba5059b9 100644 (file)
@@ -46,6 +46,23 @@ if test "$enable_selinux" = "yes"; then
 fi
 AC_SUBST([DL_LIB])
 
+# AppArmor support - off by default
+DL_LIB=
+AC_SUBST([WITH_AppArmor])
+AC_ARG_ENABLE([apparmor],
+  [AS_HELP_STRING([--enable-apparmor], [Enable AppArmor features])],
+  [enable_apparmor=$enableval],
+  [enable_apparmor="no"])
+if test "$enable_apparmor" = "yes"; then
+  AC_DEFINE([WITH_APPARMOR], [1], [Use AppArmor features])
+  AC_SEARCH_LIBS([dlopen], [dl], [],
+                [AC_MSG_ERROR([dynamic linking unavailable, circumvent with --disable-apparmor])])
+  if test "x$ac_cv_search_dlopen" != "xnone required"; then
+      DL_LIB="$ac_cv_search_dlopen"
+  fi
+fi
+AC_SUBST([DL_LIB])
+
 # Call fork before all stat calls to stop hanging on NFS mounts
 AC_SUBST([WITH_TIMEOUT_STAT])
 AC_ARG_ENABLE([timeout_stat],
index 63387cedf4dbf2b02593d5569a3030351dd7105c..02e83bb935816f98aabfab0484edbe5c8e2430de 100644 (file)
 #ifdef WITH_SELINUX
 #include <dlfcn.h>
 #include <selinux/selinux.h>
-#else
+#endif /*WITH_SELINUX */
+
+#ifdef WITH_APPARMOR
+#include <dlfcn.h>
+#include <sys/apparmor.h>
+#endif /* WITH_APPARMOR */
+
+#if !defined(WITH_SELINUX) && !defined(WITH_APPARMOR)
 typedef void* security_context_t; /* DUMMY to remove most ifdefs */
-#endif                                /*WITH_SELINUX */
+#endif /* !WITH_SELINUX && !WITH_APPARMOR  */
 
 extern const char *__progname;
 
@@ -503,6 +510,39 @@ static bool out_selinux_context(const PROC *current)
 }
 #endif /* WITH_SELINUX */
 
+#ifdef WITH_APPARMOR
+static bool out_apparmor_context(const PROC *current)
+{
+    static int (*my_aa_gettaskcon)(pid_t pid, char **context, char **mode) = 0;
+    static int (*my_aa_is_enabled)(void) = 0;
+    static int apparmor_enabled = 0;
+    static int tried_load = 0;
+    bool ret = false;
+    char *context;
+
+    if (!my_aa_gettaskcon && !tried_load) {
+        void *handle = dlopen("libapparmor.so.1", RTLD_NOW);
+        if (handle) {
+            my_aa_gettaskcon = dlsym(handle, "aa_gettaskcon");
+            if (dlerror())
+                my_aa_gettaskcon = 0;
+            my_aa_is_enabled = dlsym(handle, "aa_is_enabled");
+            if (dlerror())
+                my_aa_is_enabled = 0;
+            else
+                apparmor_enabled = my_aa_is_enabled();
+        }
+        tried_load++;
+    }
+    if (my_aa_gettaskcon && apparmor_enabled && my_aa_gettaskcon(current->pid, &context, NULL) >= 0) {
+        out_string(context);
+        free(context);
+        ret = true;
+    }
+    return ret;
+}
+#endif /* WITH_APPARMOR */
+
 /*
  * Print the security context of the current process. This is largely lifted
  * from pr_context from procps ps/output.c
@@ -516,6 +556,10 @@ static void out_scontext(const PROC *current)
     success = out_selinux_context(current);
 #endif /* WITH_SELINUX */
 
+#ifdef WITH_APPARMOR
+    success |= out_apparmor_context(current);
+#endif /* WITH_APPARMOR */
+
     if (!success) {
         FILE *file;
         char path[50];