[Sanitizers] intercept FreeBSD procctl

Reviewers: vitalybuka, emaster

Reviewed-By: viatelybuka

Differential Revision: https://reviews.llvm.org/D127069
This commit is contained in:
David CARLIER 2022-06-08 08:55:10 +01:00
parent 6eb0f8e285
commit c06ef17359
7 changed files with 114 additions and 1 deletions

View 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;

View 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

View 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);

View File

@ -593,6 +593,7 @@
#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

View 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;

View 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,

View File

@ -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;
}