Message ID | 1584006083-28936-1-git-send-email-chenhc@lemote.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [Resend] MIPS: Add syscall auditing support | expand |
CC audit maintainers and audit mail-list. Huacai On Thu, Mar 12, 2020 at 5:33 PM Huacai Chen <chenhc@lemote.com> wrote: > > From: Ralf Baechle <ralf@linux-mips.org> > > 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 <ralf@linux-mips.org> > Signed-off-by: Huacai Chen <chenhc@lemote.com> > --- > 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 >
On Mon, Apr 27, 2020 at 5:12 AM Huacai Chen <chenhuacai@gmail.com> wrote: > On Thu, Mar 12, 2020 at 5:33 PM Huacai Chen <chenhc@lemote.com> wrote: > > > > From: Ralf Baechle <ralf@linux-mips.org> > > > > 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. I'm sure you're aware of the hacky nature of such a change and considering that it is a break in the kernel/userspace API, hacky changes make me nervous. Very nervous. The ultimate fix for this would be to move away from passing structs across netlink and use netlink attributes; this would allow us the flexibility to tweak the fields like we would need for this without completely breaking existing systems. However, that is a big chunk of work (and I'm just talking about the control plane, not the audit records themselves as has been discussed in the past) and I can understand if that is not something you want to take on at this point. A less disruptive, but even more of an awful hack would be to extend past the end of the audit_rule_data struct with an audit_rule_data_ext (?) struct (perhaps indicated by a flag), but that is tricky due the variable length buffer at the end of audit_rule_data. I *really* dislike this idea, but it is *an* idea. I'm open to suggestions, but my current leaning is that if we are going to add support for MIPS, we'll need to actually do the work to convert the netlink control plane to use netlink attributes. > > - 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? Forgive my ignorance of MIPS, but as I understand it there is 32-bit MIPS (old-ABI), 64-bit MIPS (new-ABI), and 64/32-bit MIPS (new-API, aka N32); with each having both little and big endian variants, is that correct? Is it also safe to assume that 64-bit MIPS (new-API) can only run 64-bit new-API and N32 binaries and *not* 32-bit old-API binaries? I'm guessing MIPS does not support running both little and big endian binaries simultaneously on the same booted system? Or does it?
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; }