Blob Blame History Raw
From cec06ec8282c538a40bde968ae36fe8356daffaa Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Tue, 10 Apr 2012 13:31:55 +0200
Subject: [PATCH] Warn when we fail to trace and SELinux boolean deny_ptrace
 is in effect

---
 ChangeLog                 |    7 ++++++
 common.h                  |    4 +++
 configure.ac              |    5 ++++
 proc.c                    |    1 +
 sysdeps/linux-gnu/trace.c |   51 ++++++++++++++++++++++++++++++++++++--------
 5 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/common.h b/common.h
index fa80076..2399e29 100644
--- a/common.h
+++ b/common.h
@@ -359,2 +359,6 @@ extern int linkmap_init(Process *, struct ltelf *);
 
+/* Called when trace_me or primary trace_pid fail.  This may plug in
+ * any platform-specific knowledge of why it could be so.  */
+void trace_fail_warning(pid_t pid);
+
 
diff --git a/configure.ac b/configure.ac
index 7fcfda5..42d6158 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,11 @@ AC_CHECK_LIB([supc++], [__cxa_demangle], [
 AC_SUBST(libsupcxx_LIBS)
 
 
+dnl Check security_get_boolean_active availability.
+AC_CHECK_HEADERS(selinux/selinux.h)
+AC_CHECK_LIB(selinux, security_get_boolean_active)
+
+
 # HAVE_LIBUNWIND
 AC_ARG_WITH(libunwind,
   AS_HELP_STRING([--with-libunwind], [Use libunwind frame unwinding support]),
diff -up ltrace-0.6.0/configure\~ ltrace-0.6.0/configure
--- ltrace-0.6.0/configure~	2012-04-11 12:56:00.688263027 +0200
+++ ltrace-0.6.0/configure	2012-04-11 12:55:49.787935890 +0200
@@ -11029,6 +11689,65 @@ fi
 
 
 
+for ac_header in selinux/selinux.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default"
+if test "x$ac_cv_header_selinux_selinux_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SELINUX_SELINUX_H 1
+_ACEOF
+
+fi
+
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for security_get_boolean_active in -lselinux" >&5
+$as_echo_n "checking for security_get_boolean_active in -lselinux... " >&6; }
+if ${ac_cv_lib_selinux_security_get_boolean_active+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lselinux  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char security_get_boolean_active ();
+int
+main ()
+{
+return security_get_boolean_active ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_selinux_security_get_boolean_active=yes
+else
+  ac_cv_lib_selinux_security_get_boolean_active=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_security_get_boolean_active" >&5
+$as_echo "$ac_cv_lib_selinux_security_get_boolean_active" >&6; }
+if test "x$ac_cv_lib_selinux_security_get_boolean_active" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSELINUX 1
+_ACEOF
+
+  LIBS="-lselinux $LIBS"
+
+fi
+
+
+
 # HAVE_LIBUNWIND
 
 # Check whether --with-libunwind was given.
diff --git a/proc.c b/proc.c
index 106b6a0..ded0c95 100644
--- a/proc.c
+++ b/proc.c
@@ -94,6 +94,7 @@ open_pid(pid_t pid)
 	if (open_one_pid(pid)) {
 		fprintf(stderr, "Cannot attach to pid %u: %s\n",
 			pid, strerror(errno));
+		trace_fail_warning(pid);
 		return;
 	}
 
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 67e1f93..82a4154 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -10,2 +10,7 @@
 
+#include "config.h"
+#ifdef HAVE_LIBSELINUX
+# include <selinux/selinux.h>
+#endif
+
 /* If the system headers did not provide the constants, hard-code the normal
@@ -69,10 +75,32 @@ umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
 #endif
 
 void
-trace_me(void) {
+trace_fail_warning(pid_t pid)
+{
+	/* This was adapted from GDB.  */
+#ifdef HAVE_LIBSELINUX
+	static int checked = 0;
+	if (checked)
+		return;
+	checked = 1;
+
+	/* -1 is returned for errors, 0 if it has no effect, 1 if
+	 * PTRACE_ATTACH is forbidden.  */
+	if (security_get_boolean_active("deny_ptrace") == 1)
+		fprintf(stderr,
+"The SELinux boolean 'deny_ptrace' is enabled, which may prevent ltrace from\n"
+"tracing other processes.  You can disable this process attach protection by\n"
+"issuing 'setsebool deny_ptrace=0' in the superuser context.\n");
+#endif /* HAVE_LIBSELINUX */
+}
+
+void
+trace_me(void)
+{
 	debug(DEBUG_PROCESS, "trace_me: pid=%d", getpid());
 	if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
 		perror("PTRACE_TRACEME");
+		trace_fail_warning(getpid());
 		exit(1);
 	}
 }
@@ -101,11 +129,14 @@ I'll now try to proceed with tracing, but this shouldn't be happening.\n");
 }
 
 int
-trace_pid(pid_t pid) {
+trace_pid(pid_t pid)
+{
 	debug(DEBUG_PROCESS, "trace_pid: pid=%d", pid);
-	if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
+	/* This shouldn't emit error messages, as there are legitimate
+	 * reasons that the PID can't be attached: like it may have
+	 * already ended.  */
+	if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0)
 		return -1;
-	}
 
 	/* man ptrace: PTRACE_ATTACH attaches to the process specified
 	   in pid.  The child is sent a SIGSTOP, but will not
-- 
1.7.7.6

diff -up ./config.h.in~ ./config.h.in
--- ./config.h.in~	2011-02-14 17:01:18.000000000 +0100
+++ ./config.h.in	2012-04-11 13:19:10.000000000 +0200
@@ -45,6 +45,9 @@
 /* we have libiberty */
 #undef HAVE_LIBIBERTY
 
+/* Define to 1 if you have the `selinux' library (-lselinux). */
+#undef HAVE_LIBSELINUX
+
 /* we have libsupc++ */
 #undef HAVE_LIBSUPC__
 
@@ -72,6 +75,9 @@
 /* Define to 1 if you have the `rmdir' function. */
 #undef HAVE_RMDIR
 
+/* Define to 1 if you have the <selinux/selinux.h> header file. */
+#undef HAVE_SELINUX_SELINUX_H
+
 /* Define to 1 if you have the <stddef.h> header file. */
 #undef HAVE_STDDEF_H