CC audit maintainers and audit mail-list. Huacai
On Thu, Mar 12, 2020 at 5:33 PM Huacai Chen <[email protected]> wrote: > > From: Ralf Baechle <[email protected]> > > The original patch is from Ralf. I have maintained it for more than six > years on Loongson platform, and it works perfectly. Most of the commit > messages are written by Ralf. > > MIPS doesn't quite fit into the existing pattern of other architectures > and I'd appreciate your comments and maybe even an Acked-by. > > - Linux on MIPS extends the traditional syscall table used by older UNIX > implementations. This is why 32-bit Linux syscalls are starting from > 4000; the native 64-bit syscalls start from 5000 and the N32 compat ABI > from 6000. The existing syscall bitmap is only large enough for at most > 2048 syscalls, so I had to increase AUDIT_BITMASK_SIZE to 256 which > provides enough space for 8192 syscalls. Because include/uapi/linux/ > audit.h and AUDIT_BITMASK_SIZE are exported to userspace I've used an > #ifdef __mips__ for this. > > - The code treats the little endian MIPS architecture as separate from > big endian. Combined with the 3 ABIs that's 6 combinations. I tried > to sort of follow the example set by ARM which explicitly lists the > (rare) big endian architecture variant - but it doesn't seem to very > useful so I wonder if this could be squashed to just the three ABIs > without consideration of endianess? > > Signed-off-by: Ralf Baechle <[email protected]> > Signed-off-by: Huacai Chen <[email protected]> > --- > arch/mips/Kconfig | 13 +++++ > arch/mips/include/asm/abi.h | 1 + > arch/mips/include/asm/unistd.h | 10 ++++ > arch/mips/include/uapi/asm/unistd.h | 21 ++++---- > arch/mips/kernel/Makefile | 4 ++ > arch/mips/kernel/audit-n32.c | 58 ++++++++++++++++++++++ > arch/mips/kernel/audit-native.c | 97 > +++++++++++++++++++++++++++++++++++++ > arch/mips/kernel/audit-o32.c | 60 +++++++++++++++++++++++ > arch/mips/kernel/signal.c | 18 +++++++ > arch/mips/kernel/signal_n32.c | 8 +++ > arch/mips/kernel/signal_o32.c | 8 +++ > include/uapi/linux/audit.h | 10 ++++ > kernel/auditsc.c | 13 +++++ > 13 files changed, 312 insertions(+), 9 deletions(-) > create mode 100644 arch/mips/kernel/audit-n32.c > create mode 100644 arch/mips/kernel/audit-native.c > create mode 100644 arch/mips/kernel/audit-o32.c > > diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig > index 27f800f..ac71fb0 100644 > --- a/arch/mips/Kconfig > +++ b/arch/mips/Kconfig > @@ -17,6 +17,7 @@ config MIPS > select ARCH_USE_QUEUED_SPINLOCKS > select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU > select ARCH_WANT_IPC_PARSE_VERSION > + select AUDIT_ARCH > select BUILDTIME_TABLE_SORT > select CLONE_BACKWARDS > select CPU_NO_EFFICIENT_FFS if (TARGET_ISA_REV < 1) > @@ -40,6 +41,7 @@ config MIPS > select GENERIC_TIME_VSYSCALL > select GUP_GET_PTE_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT > select HANDLE_DOMAIN_IRQ > + select HAVE_ARCH_AUDITSYSCALL > select HAVE_ARCH_COMPILER_H > select HAVE_ARCH_JUMP_LABEL > select HAVE_ARCH_KGDB > @@ -1121,6 +1123,15 @@ config FW_ARC > config ARCH_MAY_HAVE_PC_FDC > bool > > +config AUDIT_ARCH > + bool > + > +config AUDITSYSCALL_O32 > + bool > + > +config AUDITSYSCALL_N32 > + bool > + > config BOOT_RAW > bool > > @@ -3192,6 +3203,7 @@ config MIPS32_O32 > select COMPAT > select MIPS32_COMPAT > select SYSVIPC_COMPAT if SYSVIPC > + select AUDITSYSCALL_O32 if AUDITSYSCALL > help > Select this option if you want to run o32 binaries. These are pure > 32-bit binaries as used by the 32-bit Linux/MIPS port. Most of > @@ -3206,6 +3218,7 @@ config MIPS32_N32 > select COMPAT > select MIPS32_COMPAT > select SYSVIPC_COMPAT if SYSVIPC > + select AUDITSYSCALL_N32 if AUDITSYSCALL > help > Select this option if you want to run n32 binaries. These are > 64-bit binaries using 32-bit quantities for addressing and certain > diff --git a/arch/mips/include/asm/abi.h b/arch/mips/include/asm/abi.h > index dba7f4b..6e717a4a 100644 > --- a/arch/mips/include/asm/abi.h > +++ b/arch/mips/include/asm/abi.h > @@ -21,6 +21,7 @@ struct mips_abi { > int (* const setup_rt_frame)(void *sig_return, struct ksignal *ksig, > struct pt_regs *regs, sigset_t *set); > const unsigned long restart; > + const int audit_arch; > > unsigned off_sc_fpregs; > unsigned off_sc_fpc_csr; > diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h > index 5d70bab..80f5b5b 100644 > --- a/arch/mips/include/asm/unistd.h > +++ b/arch/mips/include/asm/unistd.h > @@ -59,4 +59,14 @@ > > #endif /* !__ASSEMBLY__ */ > > +#ifdef CONFIG_MIPS32_N32 > +#define NR_syscalls (__NR_N32_Linux + __NR_N32_Linux_syscalls) > +#elif defined(CONFIG_64BIT) > +#define NR_syscalls (__NR_64_Linux + __NR_64_Linux_syscalls) > +#elif defined(CONFIG_32BIT) > +#define NR_syscalls (__NR_O32_Linux + __NR_O32_Linux_syscalls) > +#else > +#error Must know ABIs in use to define NR_syscalls > +#endif > + > #endif /* _ASM_UNISTD_H */ > diff --git a/arch/mips/include/uapi/asm/unistd.h > b/arch/mips/include/uapi/asm/unistd.h > index 4abe387..b501ea1 100644 > --- a/arch/mips/include/uapi/asm/unistd.h > +++ b/arch/mips/include/uapi/asm/unistd.h > @@ -6,34 +6,37 @@ > * > * Copyright (C) 1995, 96, 97, 98, 99, 2000 by Ralf Baechle > * Copyright (C) 1999, 2000 Silicon Graphics, Inc. > - * > - * Changed system calls macros _syscall5 - _syscall7 to push args 5 to 7 onto > - * the stack. Robin Farine for ACN S.A, Copyright (C) 1996 by ACN S.A > */ > #ifndef _UAPI_ASM_UNISTD_H > #define _UAPI_ASM_UNISTD_H > > #include <asm/sgidefs.h> > > -#if _MIPS_SIM == _MIPS_SIM_ABI32 > +#if (defined(__WANT_SYSCALL_NUMBERS) && > \ > + (__WANT_SYSCALL_NUMBERS == _MIPS_SIM_ABI32)) || \ > + (!defined(__WANT_SYSCALL_NUMBERS) && _MIPS_SIM == _MIPS_SIM_ABI32) > > #define __NR_Linux 4000 > #include <asm/unistd_o32.h> > > -#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ > +#endif /* Want O32 || _MIPS_SIM == _MIPS_SIM_ABI32 */ > > -#if _MIPS_SIM == _MIPS_SIM_ABI64 > +#if (defined(__WANT_SYSCALL_NUMBERS) && > \ > + (__WANT_SYSCALL_NUMBERS == _MIPS_SIM_ABI64)) || \ > + (!defined(__WANT_SYSCALL_NUMBERS) && _MIPS_SIM == _MIPS_SIM_ABI64) > > #define __NR_Linux 5000 > #include <asm/unistd_n64.h> > > -#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ > +#endif /* Want N64 || _MIPS_SIM == _MIPS_SIM_ABI64 */ > > -#if _MIPS_SIM == _MIPS_SIM_NABI32 > +#if (defined(__WANT_SYSCALL_NUMBERS) && > \ > + (__WANT_SYSCALL_NUMBERS == _MIPS_SIM_NABI32)) || \ > + (!defined(__WANT_SYSCALL_NUMBERS) && _MIPS_SIM == _MIPS_SIM_NABI32) > > #define __NR_Linux 6000 > #include <asm/unistd_n32.h> > > -#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ > +#endif /* Want N32 || _MIPS_SIM == _MIPS_SIM_NABI32 */ > > #endif /* _UAPI_ASM_UNISTD_H */ > diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile > index d6e97df..a7ac38d 100644 > --- a/arch/mips/kernel/Makefile > +++ b/arch/mips/kernel/Makefile > @@ -106,6 +106,10 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o > obj-$(CONFIG_JUMP_LABEL) += jump_label.o > obj-$(CONFIG_UPROBES) += uprobes.o > > +obj-$(CONFIG_AUDITSYSCALL_O32) += audit-o32.o > +obj-$(CONFIG_AUDITSYSCALL_N32) += audit-n32.o > +obj-$(CONFIG_AUDITSYSCALL) += audit-native.o > + > obj-$(CONFIG_MIPS_CM) += mips-cm.o > obj-$(CONFIG_MIPS_CPC) += mips-cpc.o > > diff --git a/arch/mips/kernel/audit-n32.c b/arch/mips/kernel/audit-n32.c > new file mode 100644 > index 00000000..2248badc > --- /dev/null > +++ b/arch/mips/kernel/audit-n32.c > @@ -0,0 +1,58 @@ > +#define __WANT_SYSCALL_NUMBERS _MIPS_SIM_NABI32 > + > +#include <linux/init.h> > +#include <linux/types.h> > +#include <linux/audit.h> > +#include <asm/unistd.h> > + > +static unsigned dir_class_n32[] = { > +#include <asm-generic/audit_dir_write.h> > +~0U > +}; > + > +static unsigned read_class_n32[] = { > +#include <asm-generic/audit_read.h> > +~0U > +}; > + > +static unsigned write_class_n32[] = { > +#include <asm-generic/audit_write.h> > +~0U > +}; > + > +static unsigned chattr_class_n32[] = { > +#include <asm-generic/audit_change_attr.h> > +~0U > +}; > + > +static unsigned signal_class_n32[] = { > +#include <asm-generic/audit_signal.h> > +~0U > +}; > + > +int audit_classify_syscall_n32(int abi, unsigned syscall) > +{ > + switch (syscall) { > + case __NR_open: > + return 2; > + case __NR_openat: > + return 3; > + case __NR_execve: > + return 5; > + default: > + return 0; > + } > +} > + > +static int __init audit_classes_n32_init(void) > +{ > + audit_register_class(AUDIT_CLASS_WRITE_N32, write_class_n32); > + audit_register_class(AUDIT_CLASS_READ_N32, read_class_n32); > + audit_register_class(AUDIT_CLASS_DIR_WRITE_N32, dir_class_n32); > + audit_register_class(AUDIT_CLASS_CHATTR_N32, chattr_class_n32); > + audit_register_class(AUDIT_CLASS_SIGNAL_N32, signal_class_n32); > + > + return 0; > +} > + > +__initcall(audit_classes_n32_init); > diff --git a/arch/mips/kernel/audit-native.c b/arch/mips/kernel/audit-native.c > new file mode 100644 > index 00000000..09ae3db > --- /dev/null > +++ b/arch/mips/kernel/audit-native.c > @@ -0,0 +1,97 @@ > +#include <linux/init.h> > +#include <linux/types.h> > +#include <linux/audit.h> > +#include <asm/unistd.h> > + > +static unsigned dir_class[] = { > +#include <asm-generic/audit_dir_write.h> > +~0U > +}; > + > +static unsigned read_class[] = { > +#include <asm-generic/audit_read.h> > +~0U > +}; > + > +static unsigned write_class[] = { > +#include <asm-generic/audit_write.h> > +~0U > +}; > + > +static unsigned chattr_class[] = { > +#include <asm-generic/audit_change_attr.h> > +~0U > +}; > + > +static unsigned signal_class[] = { > +#include <asm-generic/audit_signal.h> > +~0U > +}; > + > + > +/* > + * Pretend to be a single architecture > + */ > +int audit_classify_arch(int arch) > +{ > + return 0; > +} > + > +extern int audit_classify_syscall_o32(int abi, unsigned syscall); > +extern int audit_classify_syscall_n32(int abi, unsigned syscall); > + > +int audit_classify_syscall(int abi, unsigned syscall) > +{ > + int res; > + > + switch (syscall) { > + case __NR_open: > + res = 2; > + break; > + > + case __NR_openat: > + res = 3; > + break; > + > +#ifdef __NR_socketcall /* Only exists on O32 */ > + case __NR_socketcall: > + res = 4; > + break; > +#endif > + case __NR_execve: > + res = 5; > + break; > + default: > +#ifdef CONFIG_AUDITSYSCALL_O32 > + res = audit_classify_syscall_o32(abi, syscall); > + if (res) > + break; > +#endif > +#ifdef CONFIG_AUDITSYSCALL_N32 > + res = audit_classify_syscall_n32(abi, syscall); > + if (res) > + break; > +#endif > + if (abi == AUDIT_ARCH_MIPS || abi == AUDIT_ARCH_MIPSEL) > + res = 1; > + else if (abi == AUDIT_ARCH_MIPS64 || abi == > AUDIT_ARCH_MIPSEL64) > + res = 0; > + else if (abi == AUDIT_ARCH_MIPS64N32 || abi == > AUDIT_ARCH_MIPSEL64N32) > + res = 6; > + } > + > + return res; > +} > + > +static int __init audit_classes_init(void) > +{ > + audit_register_class(AUDIT_CLASS_WRITE, write_class); > + audit_register_class(AUDIT_CLASS_READ, read_class); > + audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class); > + audit_register_class(AUDIT_CLASS_CHATTR, chattr_class); > + audit_register_class(AUDIT_CLASS_SIGNAL, signal_class); > + > + return 0; > +} > + > +__initcall(audit_classes_init); > diff --git a/arch/mips/kernel/audit-o32.c b/arch/mips/kernel/audit-o32.c > new file mode 100644 > index 00000000..e8b9b50 > --- /dev/null > +++ b/arch/mips/kernel/audit-o32.c > @@ -0,0 +1,60 @@ > +#define __WANT_SYSCALL_NUMBERS _MIPS_SIM_ABI32 > + > +#include <linux/init.h> > +#include <linux/types.h> > +#include <linux/audit.h> > +#include <linux/unistd.h> > + > +static unsigned dir_class_o32[] = { > +#include <asm-generic/audit_dir_write.h> > +~0U > +}; > + > +static unsigned read_class_o32[] = { > +#include <asm-generic/audit_read.h> > +~0U > +}; > + > +static unsigned write_class_o32[] = { > +#include <asm-generic/audit_write.h> > +~0U > +}; > + > +static unsigned chattr_class_o32[] = { > +#include <asm-generic/audit_change_attr.h> > +~0U > +}; > + > +static unsigned signal_class_o32[] = { > +#include <asm-generic/audit_signal.h> > +~0U > +}; > + > +int audit_classify_syscall_o32(int abi, unsigned syscall) > +{ > + switch (syscall) { > + case __NR_open: > + return 2; > + case __NR_openat: > + return 3; > + case __NR_socketcall: > + return 4; > + case __NR_execve: > + return 5; > + default: > + return 0; > + } > +} > + > +static int __init audit_classes_o32_init(void) > +{ > + audit_register_class(AUDIT_CLASS_WRITE_32, write_class_o32); > + audit_register_class(AUDIT_CLASS_READ_32, read_class_o32); > + audit_register_class(AUDIT_CLASS_DIR_WRITE_32, dir_class_o32); > + audit_register_class(AUDIT_CLASS_CHATTR_32, chattr_class_o32); > + audit_register_class(AUDIT_CLASS_SIGNAL_32, signal_class_o32); > + > + return 0; > +} > + > +__initcall(audit_classes_o32_init); > diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c > index f6efabc..b79d9a9 100644 > --- a/arch/mips/kernel/signal.c > +++ b/arch/mips/kernel/signal.c > @@ -8,6 +8,7 @@ > * Copyright (C) 1999, 2000 Silicon Graphics, Inc. > * Copyright (C) 2014, Imagination Technologies Ltd. > */ > +#include <linux/audit.h> > #include <linux/cache.h> > #include <linux/context_tracking.h> > #include <linux/irqflags.h> > @@ -790,6 +791,23 @@ struct mips_abi mips_abi = { > #endif > .setup_rt_frame = setup_rt_frame, > .restart = __NR_restart_syscall, > +#ifdef CONFIG_64BIT > +# ifdef __BIG_ENDIAN > + .audit_arch = AUDIT_ARCH_MIPS64, > +# elif defined(__LITTLE_ENDIAN) > + .audit_arch = AUDIT_ARCH_MIPSEL64, > +# else > +# error "Neither big nor little endian ???" > +# endif > +#else > +# ifdef __BIG_ENDIAN > + .audit_arch = AUDIT_ARCH_MIPS, > +# elif defined(__LITTLE_ENDIAN) > + .audit_arch = AUDIT_ARCH_MIPSEL, > +# else > +# error "Neither big nor little endian ???" > +# endif > +#endif > > .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), > .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), > diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c > index 7bd00fa..ed03ea1 100644 > --- a/arch/mips/kernel/signal_n32.c > +++ b/arch/mips/kernel/signal_n32.c > @@ -2,6 +2,7 @@ > /* > * Copyright (C) 2003 Broadcom Corporation > */ > +#include <linux/audit.h> > #include <linux/cache.h> > #include <linux/sched.h> > #include <linux/mm.h> > @@ -140,6 +141,13 @@ static int setup_rt_frame_n32(void *sig_return, struct > ksignal *ksig, > struct mips_abi mips_abi_n32 = { > .setup_rt_frame = setup_rt_frame_n32, > .restart = __NR_N32_restart_syscall, > +#ifdef __BIG_ENDIAN > + .audit_arch = AUDIT_ARCH_MIPS64N32, > +#elif defined(__LITTLE_ENDIAN) > + .audit_arch = AUDIT_ARCH_MIPSEL64N32, > +#else > +# error "Neither big nor little endian ???" > +#endif > > .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), > .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), > diff --git a/arch/mips/kernel/signal_o32.c b/arch/mips/kernel/signal_o32.c > index 299a7a2..9f4ad0a 100644 > --- a/arch/mips/kernel/signal_o32.c > +++ b/arch/mips/kernel/signal_o32.c > @@ -8,6 +8,7 @@ > * Copyright (C) 1999, 2000 Silicon Graphics, Inc. > * Copyright (C) 2016, Imagination Technologies Ltd. > */ > +#include <linux/audit.h> > #include <linux/compiler.h> > #include <linux/errno.h> > #include <linux/signal.h> > @@ -244,6 +245,13 @@ struct mips_abi mips_abi_32 = { > .setup_frame = setup_frame_32, > .setup_rt_frame = setup_rt_frame_32, > .restart = __NR_O32_restart_syscall, > +#ifdef __BIG_ENDIAN > + .audit_arch = AUDIT_ARCH_MIPS, > +#elif defined(__LITTLE_ENDIAN) > + .audit_arch = AUDIT_ARCH_MIPSEL, > +#else > +# error "Neither big nor little endian ???" > +#endif > > .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), > .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), > diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h > index a534d71..336c1eb 100644 > --- a/include/uapi/linux/audit.h > +++ b/include/uapi/linux/audit.h > @@ -179,7 +179,11 @@ > * AUDIT_LIST commands must be implemented. */ > #define AUDIT_MAX_FIELDS 64 > #define AUDIT_MAX_KEY_LEN 256 > +#ifdef __mips__ > +#define AUDIT_BITMASK_SIZE 256 > +#else > #define AUDIT_BITMASK_SIZE 64 > +#endif > #define AUDIT_WORD(nr) ((__u32)((nr)/32)) > #define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32)) > > @@ -195,6 +199,12 @@ > #define AUDIT_CLASS_SIGNAL 8 > #define AUDIT_CLASS_SIGNAL_32 9 > > +#define AUDIT_CLASS_DIR_WRITE_N32 10 > +#define AUDIT_CLASS_CHATTR_N32 11 > +#define AUDIT_CLASS_READ_N32 12 > +#define AUDIT_CLASS_WRITE_N32 13 > +#define AUDIT_CLASS_SIGNAL_N32 14 > + > /* This bitmask is used to validate user input. It represents all bits that > * are currently used in an audit field constant understood by the kernel. > * If you are adding a new #define AUDIT_<whatever>, please ensure that > diff --git a/kernel/auditsc.c b/kernel/auditsc.c > index 4effe01..cf223c0 100644 > --- a/kernel/auditsc.c > +++ b/kernel/auditsc.c > @@ -168,6 +168,19 @@ static int audit_match_perm(struct audit_context *ctx, > int mask) > return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == > SYS_BIND); > case 5: /* execve */ > return mask & AUDIT_PERM_EXEC; > +#ifdef CONFIG_MIPS > + case 6: /* for N32 */ > + if ((mask & AUDIT_PERM_WRITE) && > + audit_match_class(AUDIT_CLASS_WRITE_N32, n)) > + return 1; > + if ((mask & AUDIT_PERM_READ) && > + audit_match_class(AUDIT_CLASS_READ_N32, n)) > + return 1; > + if ((mask & AUDIT_PERM_ATTR) && > + audit_match_class(AUDIT_CLASS_CHATTR_N32, n)) > + return 1; > + return 0; > +#endif > default: > return 0; > } > -- > 2.7.0 > -- Linux-audit mailing list [email protected] https://www.redhat.com/mailman/listinfo/linux-audit
