[Sanitizers] intercept FreeBSD procctl
authorDavid CARLIER <devnexen@gmail.com>
Wed, 8 Jun 2022 07:55:10 +0000 (08:55 +0100)
committerDavid CARLIER <devnexen@gmail.com>
Wed, 8 Jun 2022 07:55:10 +0000 (08:55 +0100)
Reviewers: vitalybuka, emaster

Reviewed-By: viatelybuka
Differential Revision: https://reviews.llvm.org/D127069

compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
compiler-rt/lib/sanitizer_common/sanitizer_linux.h
compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h
compiler-rt/test/sanitizer_common/TestCases/FreeBSD/procctl.cpp [new file with mode: 0644]

index 4ab47e8..b89c66f 100644 (file)
@@ -10349,6 +10349,42 @@ INTERCEPTOR(int, sigaltstack, void *ss, void *oss) {
 #define INIT_SIGALTSTACK
 #endif
 
+#if SANITIZER_INTERCEPT_PROCCTL
+INTERCEPTOR(int, procctl, int idtype, u64 id, int cmd, uptr data) {
+   void *ctx;
+   COMMON_INTERCEPTOR_ENTER(ctx, procctl, idtype, id, cmd, data);
+   static const int PROC_REAP_ACQUIRE = 2;
+   static const int PROC_REAP_RELEASE = 3;
+   static const int PROC_REAP_STATUS = 4;
+   static const int PROC_REAP_GETPIDS = 5;
+   static const int PROC_REAP_KILL = 6;
+   if (cmd < PROC_REAP_ACQUIRE || cmd > PROC_REAP_KILL) {
+     COMMON_INTERCEPTOR_READ_RANGE(ctx, (void *)data, sizeof(int));
+   } else {
+     // reap_acquire/reap_release bears no arguments.
+     if (cmd > PROC_REAP_RELEASE) {
+       unsigned int reapsz;
+       switch (cmd) {
+       case PROC_REAP_STATUS:
+         reapsz = struct_procctl_reaper_status_sz;
+         break;
+       case PROC_REAP_GETPIDS:
+         reapsz = struct_procctl_reaper_pids_sz;
+         break;
+       case PROC_REAP_KILL:
+         reapsz = struct_procctl_reaper_kill_sz;
+         break;
+       }
+       COMMON_INTERCEPTOR_READ_RANGE(ctx, (void *)data, reapsz);
+     }
+   }
+   return REAL(procctl)(idtype, id, cmd, data);
+}
+#define INIT_PROCCTL COMMON_INTERCEPT_FUNCTION(procctl)
+#else
+#define INIT_PROCCTL
+#endif
+
 #if SANITIZER_INTERCEPT_UNAME
 INTERCEPTOR(int, uname, struct utsname *utsname) {
 #if SANITIZER_LINUX
@@ -10708,6 +10744,7 @@ static void InitializeCommonInterceptors() {
   INIT_QSORT_R;
   INIT_BSEARCH;
   INIT_SIGALTSTACK;
+  INIT_PROCCTL
   INIT_UNAME;
   INIT___XUNAME;
 
index 6c6f40a..c94d722 100644 (file)
@@ -901,6 +901,10 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
   return k_set->sig[idx] & ((uptr)1 << bit);
 }
 #elif SANITIZER_FREEBSD
+uptr internal_procctl(int type, int id, int cmd, void *data) {
+  return internal_syscall(SYSCALL(procctl), type, id, cmd, data);
+}
+
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
   sigset_t *rset = reinterpret_cast<sigset_t *>(set);
   sigdelset(rset, signum);
@@ -2186,7 +2190,8 @@ void CheckASLR() {
   }
 #elif SANITIZER_FREEBSD
   int aslr_status;
-  if (UNLIKELY(procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status) == -1)) {
+  int r = internal_procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status);
+  if (UNLIKELY(r == -1)) {
     // We're making things less 'dramatic' here since
     // the cmd is not necessarily guaranteed to be here
     // just yet regarding FreeBSD release
index ebd60e0..45d8c92 100644 (file)
@@ -82,6 +82,7 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
 #endif
 int internal_uname(struct utsname *buf);
 #elif SANITIZER_FREEBSD
+uptr internal_procctl(int type, int id, int cmd, void *data);
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
 #elif SANITIZER_NETBSD
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
index 675e0fd..f81d614 100644 (file)
 #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
 #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
 #define SANITIZER_INTERCEPT_FLOPEN SI_FREEBSD
+#define SANITIZER_INTERCEPT_PROCCTL SI_FREEBSD
 
 // This macro gives a way for downstream users to override the above
 // interceptor macros irrespective of the platform they are on. They have
index 0d25fa8..37e72cd 100644 (file)
@@ -205,6 +205,10 @@ unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
 unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
 unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
 unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+unsigned struct_procctl_reaper_status_sz = sizeof(struct __sanitizer_procctl_reaper_status);
+unsigned struct_procctl_reaper_pidinfo_sz = sizeof(struct __sanitizer_procctl_reaper_pidinfo);
+unsigned struct_procctl_reaper_pids_sz = sizeof(struct __sanitizer_procctl_reaper_pids);
+unsigned struct_procctl_reaper_kill_sz = sizeof(struct __sanitizer_procctl_reaper_kill);
 const unsigned long __sanitizer_bufsiz = BUFSIZ;
 
 const unsigned IOCTL_NOT_PRESENT = 0;
index 9859c52..daef117 100644 (file)
@@ -424,6 +424,38 @@ struct __sanitizer__ttyent {
   char *ty_group;
 };
 
+// procctl reaper data for PROCCTL_REAPER flags
+struct __sanitizer_procctl_reaper_status {
+  unsigned int rs_flags;
+  unsigned int rs_children;
+  unsigned int rs_descendants;
+  pid_t rs_reaper;
+  pid_t rs_pid;
+  unsigned int rs_pad0[15];
+};
+
+struct __sanitizer_procctl_reaper_pidinfo {
+  pid_t pi_pid;
+  pid_t pi_subtree;
+  unsigned int pi_flags;
+  unsigned int pi_pad0[15];
+};
+
+struct __sanitizer_procctl_reaper_pids {
+  unsigned int rp_count;
+  unsigned int rp_pad0[15];
+  struct __sanitize_procctl_reapper_pidinfo *rp_pids;
+};
+
+struct __sanitizer_procctl_reaper_kill {
+  int rk_sig;
+  unsigned int rk_flags;
+  pid_t rk_subtree;
+  unsigned int rk_killed;
+  pid_t rk_fpid;
+  unsigned int rk_pad[15];
+};
+
 #  define IOC_NRBITS 8
 #  define IOC_TYPEBITS 8
 #  if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__)
@@ -480,6 +512,11 @@ extern unsigned struct_ppp_stats_sz;
 extern unsigned struct_sioc_sg_req_sz;
 extern unsigned struct_sioc_vif_req_sz;
 
+extern unsigned struct_procctl_reaper_status_sz;
+extern unsigned struct_procctl_reaper_pidinfo_sz;
+extern unsigned struct_procctl_reaper_pids_sz;
+extern unsigned struct_procctl_reaper_kill_sz;
+
 // ioctl request identifiers
 
 // A special value to mark ioctls that are not present on the target platform,
diff --git a/compiler-rt/test/sanitizer_common/TestCases/FreeBSD/procctl.cpp b/compiler-rt/test/sanitizer_common/TestCases/FreeBSD/procctl.cpp
new file mode 100644 (file)
index 0000000..a5c6a5e
--- /dev/null
@@ -0,0 +1,28 @@
+// RUN: %clangxx %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/procctl.h>
+
+int main() {
+  struct procctl_reaper_status status = {0};
+  int res, aslr;
+  res = procctl(P_PID, getpid(), PROC_REAP_STATUS, &status);
+  if (res < 0) {
+    assert(errno == EPERM);
+    return 0;
+  }
+
+  assert(status.rs_flags >= REAPER_STATUS_OWNED);
+
+  res = procctl(P_PID, getpid(), PROC_ASLR_STATUS, &aslr);
+  if (res < 0) {
+    assert(errno == EPERM);
+    return 0;
+  }
+
+  assert(aslr >= PROC_ASLR_FORCE_ENABLE);
+
+  return 0;
+}