From 3b33ac3182a4554742757a0c61ee1df162cf8225 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Sat, 26 Aug 2006 14:06:20 -0400 Subject: [PATCH 1/6] [PATCH] fix ppid bug in 2.6.18 kernel Hello, During some troubleshooting, I found that ppid was accidentally omitted from the legacy rule section. This resulted in EINVAL for any rule with ppid sent with AUDIT_ADD. Signed-off-by: Steve Grubb Signed-off-by: Al Viro --- kernel/auditfilter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 6a9a5c5a4e7d..0d6a8fc21f17 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -404,6 +404,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) case AUDIT_PERS: case AUDIT_ARCH: case AUDIT_MSGTYPE: + case AUDIT_PPID: case AUDIT_DEVMAJOR: case AUDIT_DEVMINOR: case AUDIT_EXIT: From 8ef2d3040e5cf38f7d64a408038f576b4a5ec987 Mon Sep 17 00:00:00 2001 From: Amy Griffis Date: Thu, 7 Sep 2006 17:03:02 -0400 Subject: [PATCH 2/6] [PATCH] sanity check audit_buffer Add sanity checks for NULL audit_buffer consistent with other audit_log* routines. Signed-off-by: Amy Griffis Signed-off-by: Al Viro --- kernel/audit.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/audit.c b/kernel/audit.c index 0a36091ed712..963fd15c9621 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1028,6 +1028,9 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, struct sk_buff *skb; static const unsigned char *hex = "0123456789ABCDEF"; + if (!ab) + return; + BUG_ON(!ab->skb); skb = ab->skb; avail = skb_tailroom(skb); @@ -1060,6 +1063,9 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen, unsigned char *ptr; struct sk_buff *skb; + if (!ab) + return; + BUG_ON(!ab->skb); skb = ab->skb; avail = skb_tailroom(skb); From 5974501e2d44546748e67c635cec20ba66619a3d Mon Sep 17 00:00:00 2001 From: Amy Griffis Date: Thu, 7 Sep 2006 17:46:18 -0400 Subject: [PATCH 3/6] [PATCH] update audit rule change messages Make the audit message for implicit rule removal more informative. Make the rule update message consistent with other messages. Signed-off-by: Amy Griffis Signed-off-by: Al Viro --- kernel/auditfilter.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 0d6a8fc21f17..e4cafc11c510 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -914,7 +914,7 @@ static void audit_update_watch(struct audit_parent *parent, } ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - audit_log_format(ab, "audit updated rules specifying watch="); + audit_log_format(ab, "audit updated rules specifying path="); audit_log_untrustedstring(ab, owatch->path); audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino); audit_log_end(ab); @@ -937,19 +937,28 @@ static void audit_remove_parent_watches(struct audit_parent *parent) struct audit_watch *w, *nextw; struct audit_krule *r, *nextr; struct audit_entry *e; + struct audit_buffer *ab; mutex_lock(&audit_filter_mutex); parent->flags |= AUDIT_PARENT_INVALID; list_for_each_entry_safe(w, nextw, &parent->watches, wlist) { list_for_each_entry_safe(r, nextr, &w->rules, rlist) { e = container_of(r, struct audit_entry, rule); + + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); + audit_log_format(ab, "audit implicitly removed rule path="); + audit_log_untrustedstring(ab, w->path); + if (r->filterkey) { + audit_log_format(ab, " key="); + audit_log_untrustedstring(ab, r->filterkey); + } else + audit_log_format(ab, " key=(null)"); + audit_log_format(ab, " list=%d", r->listnr); + audit_log_end(ab); + list_del(&r->rlist); list_del_rcu(&e->list); call_rcu(&e->rcu, audit_free_rule_rcu); - - audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, - "audit implicitly removed rule from list=%d\n", - AUDIT_FILTER_EXIT); } audit_remove_watch(w); } From c08037997d4ae3e9a679fbdb46ed47c957916e14 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 31 Aug 2006 19:02:42 -0400 Subject: [PATCH 4/6] [PATCH] syscall classes hookup for ppc and s390 Signed-off-by: Al Viro --- arch/powerpc/kernel/Makefile | 2 ++ arch/powerpc/kernel/audit.c | 29 +++++++++++++++++++++++++++++ arch/powerpc/kernel/compat_audit.c | 12 ++++++++++++ arch/s390/kernel/Makefile | 4 +++- arch/s390/kernel/audit.c | 29 +++++++++++++++++++++++++++++ arch/s390/kernel/compat_audit.c | 12 ++++++++++++ 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/kernel/audit.c create mode 100644 arch/powerpc/kernel/compat_audit.c create mode 100644 arch/s390/kernel/audit.c create mode 100644 arch/s390/kernel/compat_audit.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 956c2e5564b7..7d32ad0194a4 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -70,6 +70,8 @@ obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) kexec-$(CONFIG_PPC64) := machine_kexec_64.o kexec-$(CONFIG_PPC32) := machine_kexec_32.o obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y) +obj-$(CONFIG_AUDIT) += audit.o +obj64-$(CONFIG_AUDIT) += compat_audit.o ifeq ($(CONFIG_PPC_ISERIES),y) $(obj)/head_64.o: $(obj)/lparmap.s diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c new file mode 100644 index 000000000000..caf085a19234 --- /dev/null +++ b/arch/powerpc/kernel/audit.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +static unsigned dir_class[] = { +#include +~0U +}; + +static unsigned chattr_class[] = { +#include +~0U +}; + +static int __init audit_classes_init(void) +{ +#ifdef CONFIG_PPC64 + extern __u32 ppc32_dir_class[]; + extern __u32 ppc32_chattr_class[]; + audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ppc32_dir_class); + audit_register_class(AUDIT_CLASS_CHATTR_32, ppc32_chattr_class); +#endif + audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class); + audit_register_class(AUDIT_CLASS_CHATTR, chattr_class); + return 0; +} + +__initcall(audit_classes_init); diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c new file mode 100644 index 000000000000..dbbb8b81f1d9 --- /dev/null +++ b/arch/powerpc/kernel/compat_audit.c @@ -0,0 +1,12 @@ +#undef __powerpc64__ +#include + +unsigned ppc32_dir_class[] = { +#include +~0U +}; + +unsigned ppc32_chattr_class[] = { +#include +~0U +}; diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 86601a945709..9a33ed6ca696 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -16,9 +16,11 @@ extra-y += head.o init_task.o vmlinux.lds obj-$(CONFIG_MODULES) += s390_ksyms.o module.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_AUDIT) += audit.o +compat-obj-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ compat_wrapper.o compat_exec_domain.o \ - binfmt_elf32.o + binfmt_elf32.o $(compat-obj-y) obj-$(CONFIG_VIRT_TIMER) += vtime.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c new file mode 100644 index 000000000000..c26cd6cb2319 --- /dev/null +++ b/arch/s390/kernel/audit.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +static unsigned dir_class[] = { +#include +~0U +}; + +static unsigned chattr_class[] = { +#include +~0U +}; + +static int __init audit_classes_init(void) +{ +#ifdef CONFIG_COMPAT + extern __u32 s390_dir_class[]; + extern __u32 s390_chattr_class[]; + audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class); + audit_register_class(AUDIT_CLASS_CHATTR_32, s390_chattr_class); +#endif + audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class); + audit_register_class(AUDIT_CLASS_CHATTR, chattr_class); + return 0; +} + +__initcall(audit_classes_init); diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c new file mode 100644 index 000000000000..1a7d34fecf67 --- /dev/null +++ b/arch/s390/kernel/compat_audit.c @@ -0,0 +1,12 @@ +#undef __s390x__ +#include + +unsigned s390_dir_class[] = { +#include +~0U +}; + +unsigned s390_chattr_class[] = { +#include +~0U +}; From dc104fb3231f11e95b5a0f09ae3ab27a8fd5b2e8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 31 Aug 2006 19:05:56 -0400 Subject: [PATCH 5/6] [PATCH] audit: more syscall classes added Signed-off-by: Al Viro --- arch/i386/kernel/audit.c | 12 ++++++++++++ arch/ia64/ia32/audit.c | 10 ++++++++++ arch/ia64/kernel/audit.c | 16 ++++++++++++++++ arch/powerpc/kernel/audit.c | 16 ++++++++++++++++ arch/powerpc/kernel/compat_audit.c | 10 ++++++++++ arch/s390/kernel/audit.c | 16 ++++++++++++++++ arch/s390/kernel/compat_audit.c | 10 ++++++++++ arch/x86_64/ia32/audit.c | 10 ++++++++++ arch/x86_64/kernel/audit.c | 16 ++++++++++++++++ include/asm-generic/audit_read.h | 8 ++++++++ include/asm-generic/audit_write.h | 11 +++++++++++ include/linux/audit.h | 4 ++++ 12 files changed, 139 insertions(+) create mode 100644 include/asm-generic/audit_read.h create mode 100644 include/asm-generic/audit_write.h diff --git a/arch/i386/kernel/audit.c b/arch/i386/kernel/audit.c index 5a53c6f371ff..28bbc46f75c2 100644 --- a/arch/i386/kernel/audit.c +++ b/arch/i386/kernel/audit.c @@ -8,6 +8,16 @@ static unsigned dir_class[] = { ~0U }; +static unsigned read_class[] = { +#include +~0U +}; + +static unsigned write_class[] = { +#include +~0U +}; + static unsigned chattr_class[] = { #include ~0U @@ -15,6 +25,8 @@ static unsigned chattr_class[] = { 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); return 0; diff --git a/arch/ia64/ia32/audit.c b/arch/ia64/ia32/audit.c index ab94f2e58cdd..798501994bd9 100644 --- a/arch/ia64/ia32/audit.c +++ b/arch/ia64/ia32/audit.c @@ -9,3 +9,13 @@ unsigned ia32_chattr_class[] = { #include ~0U }; + +unsigned ia32_write_class[] = { +#include +~0U +}; + +unsigned ia32_read_class[] = { +#include +~0U +}; diff --git a/arch/ia64/kernel/audit.c b/arch/ia64/kernel/audit.c index f2512931ccaf..99488cdbf5cd 100644 --- a/arch/ia64/kernel/audit.c +++ b/arch/ia64/kernel/audit.c @@ -8,6 +8,16 @@ static unsigned dir_class[] = { ~0U }; +static unsigned read_class[] = { +#include +~0U +}; + +static unsigned write_class[] = { +#include +~0U +}; + static unsigned chattr_class[] = { #include ~0U @@ -17,10 +27,16 @@ static int __init audit_classes_init(void) { #ifdef CONFIG_IA32_SUPPORT extern __u32 ia32_dir_class[]; + extern __u32 ia32_write_class[]; + extern __u32 ia32_read_class[]; extern __u32 ia32_chattr_class[]; + audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class); + audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class); audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class); audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class); #endif + 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); return 0; diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c index caf085a19234..24a65e3724e1 100644 --- a/arch/powerpc/kernel/audit.c +++ b/arch/powerpc/kernel/audit.c @@ -8,6 +8,16 @@ static unsigned dir_class[] = { ~0U }; +static unsigned read_class[] = { +#include +~0U +}; + +static unsigned write_class[] = { +#include +~0U +}; + static unsigned chattr_class[] = { #include ~0U @@ -17,10 +27,16 @@ static int __init audit_classes_init(void) { #ifdef CONFIG_PPC64 extern __u32 ppc32_dir_class[]; + extern __u32 ppc32_write_class[]; + extern __u32 ppc32_read_class[]; extern __u32 ppc32_chattr_class[]; + audit_register_class(AUDIT_CLASS_WRITE_32, ppc32_write_class); + audit_register_class(AUDIT_CLASS_READ_32, ppc32_read_class); audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ppc32_dir_class); audit_register_class(AUDIT_CLASS_CHATTR_32, ppc32_chattr_class); #endif + 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); return 0; diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c index dbbb8b81f1d9..ddc0a64896a2 100644 --- a/arch/powerpc/kernel/compat_audit.c +++ b/arch/powerpc/kernel/compat_audit.c @@ -10,3 +10,13 @@ unsigned ppc32_chattr_class[] = { #include ~0U }; + +unsigned ppc32_write_class[] = { +#include +~0U +}; + +unsigned ppc32_read_class[] = { +#include +~0U +}; diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c index c26cd6cb2319..cde57039334c 100644 --- a/arch/s390/kernel/audit.c +++ b/arch/s390/kernel/audit.c @@ -8,6 +8,16 @@ static unsigned dir_class[] = { ~0U }; +static unsigned read_class[] = { +#include +~0U +}; + +static unsigned write_class[] = { +#include +~0U +}; + static unsigned chattr_class[] = { #include ~0U @@ -17,10 +27,16 @@ static int __init audit_classes_init(void) { #ifdef CONFIG_COMPAT extern __u32 s390_dir_class[]; + extern __u32 s390_write_class[]; + extern __u32 s390_read_class[]; extern __u32 s390_chattr_class[]; + audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class); + audit_register_class(AUDIT_CLASS_READ_32, s390_read_class); audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class); audit_register_class(AUDIT_CLASS_CHATTR_32, s390_chattr_class); #endif + 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); return 0; diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c index 1a7d34fecf67..d9e5f3540d48 100644 --- a/arch/s390/kernel/compat_audit.c +++ b/arch/s390/kernel/compat_audit.c @@ -10,3 +10,13 @@ unsigned s390_chattr_class[] = { #include ~0U }; + +unsigned s390_write_class[] = { +#include +~0U +}; + +unsigned s390_read_class[] = { +#include +~0U +}; diff --git a/arch/x86_64/ia32/audit.c b/arch/x86_64/ia32/audit.c index ab94f2e58cdd..798501994bd9 100644 --- a/arch/x86_64/ia32/audit.c +++ b/arch/x86_64/ia32/audit.c @@ -9,3 +9,13 @@ unsigned ia32_chattr_class[] = { #include ~0U }; + +unsigned ia32_write_class[] = { +#include +~0U +}; + +unsigned ia32_read_class[] = { +#include +~0U +}; diff --git a/arch/x86_64/kernel/audit.c b/arch/x86_64/kernel/audit.c index a067aa468a85..36840acb6513 100644 --- a/arch/x86_64/kernel/audit.c +++ b/arch/x86_64/kernel/audit.c @@ -8,6 +8,16 @@ static unsigned dir_class[] = { ~0U }; +static unsigned read_class[] = { +#include +~0U +}; + +static unsigned write_class[] = { +#include +~0U +}; + static unsigned chattr_class[] = { #include ~0U @@ -17,10 +27,16 @@ static int __init audit_classes_init(void) { #ifdef CONFIG_IA32_EMULATION extern __u32 ia32_dir_class[]; + extern __u32 ia32_write_class[]; + extern __u32 ia32_read_class[]; extern __u32 ia32_chattr_class[]; + audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class); + audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class); audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class); audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class); #endif + 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); return 0; diff --git a/include/asm-generic/audit_read.h b/include/asm-generic/audit_read.h new file mode 100644 index 000000000000..0e87464d9847 --- /dev/null +++ b/include/asm-generic/audit_read.h @@ -0,0 +1,8 @@ +__NR_readlink, +__NR_quotactl, +__NR_listxattr, +__NR_llistxattr, +__NR_flistxattr, +__NR_getxattr, +__NR_lgetxattr, +__NR_fgetxattr, diff --git a/include/asm-generic/audit_write.h b/include/asm-generic/audit_write.h new file mode 100644 index 000000000000..f10d367fb2a5 --- /dev/null +++ b/include/asm-generic/audit_write.h @@ -0,0 +1,11 @@ +#include +__NR_acct, +__NR_swapon, +__NR_quotactl, +__NR_truncate, +#ifdef __NR_truncate64 +__NR_truncate64, +#endif +#ifdef __NR_bind +__NR_bind, /* bind can affect fs object only in one way... */ +#endif diff --git a/include/linux/audit.h b/include/linux/audit.h index 64f9f9e56ac5..1077362a2efb 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -132,6 +132,10 @@ #define AUDIT_CLASS_DIR_WRITE_32 1 #define AUDIT_CLASS_CHATTR 2 #define AUDIT_CLASS_CHATTR_32 3 +#define AUDIT_CLASS_READ 4 +#define AUDIT_CLASS_READ_32 5 +#define AUDIT_CLASS_WRITE 6 +#define AUDIT_CLASS_WRITE_32 7 /* 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. From 55669bfa141b488be865341ed12e188967d11308 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 31 Aug 2006 19:26:40 -0400 Subject: [PATCH 6/6] [PATCH] audit: AUDIT_PERM support add support for AUDIT_PERM predicate Signed-off-by: Al Viro --- arch/i386/kernel/audit.c | 16 ++++++++++ arch/ia64/ia32/audit.c | 16 ++++++++++ arch/ia64/kernel/audit.c | 19 +++++++++++ arch/powerpc/kernel/audit.c | 21 ++++++++++++ arch/powerpc/kernel/compat_audit.c | 16 ++++++++++ arch/s390/kernel/audit.c | 21 ++++++++++++ arch/s390/kernel/compat_audit.c | 16 ++++++++++ arch/x86_64/ia32/audit.c | 16 ++++++++++ arch/x86_64/kernel/audit.c | 19 +++++++++++ include/linux/audit.h | 7 ++++ kernel/audit.h | 1 + kernel/auditfilter.c | 17 ++++++++++ kernel/auditsc.c | 51 ++++++++++++++++++++++++++++++ 13 files changed, 236 insertions(+) diff --git a/arch/i386/kernel/audit.c b/arch/i386/kernel/audit.c index 28bbc46f75c2..3b97cff41549 100644 --- a/arch/i386/kernel/audit.c +++ b/arch/i386/kernel/audit.c @@ -23,6 +23,22 @@ static unsigned chattr_class[] = { ~0U }; +int audit_classify_syscall(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_init(void) { audit_register_class(AUDIT_CLASS_WRITE, write_class); diff --git a/arch/ia64/ia32/audit.c b/arch/ia64/ia32/audit.c index 798501994bd9..92d7d0c8d93f 100644 --- a/arch/ia64/ia32/audit.c +++ b/arch/ia64/ia32/audit.c @@ -19,3 +19,19 @@ unsigned ia32_read_class[] = { #include ~0U }; + +int ia32_classify_syscall(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 1; + } +} diff --git a/arch/ia64/kernel/audit.c b/arch/ia64/kernel/audit.c index 99488cdbf5cd..04682555a28c 100644 --- a/arch/ia64/kernel/audit.c +++ b/arch/ia64/kernel/audit.c @@ -23,6 +23,25 @@ static unsigned chattr_class[] = { ~0U }; +int audit_classify_syscall(int abi, unsigned syscall) +{ +#ifdef CONFIG_IA32_SUPPORT + extern int ia32_classify_syscall(unsigned); + if (abi == AUDIT_ARCH_I386) + return ia32_classify_syscall(syscall); +#endif + 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_init(void) { #ifdef CONFIG_IA32_SUPPORT diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c index 24a65e3724e1..7fe5e6300e9a 100644 --- a/arch/powerpc/kernel/audit.c +++ b/arch/powerpc/kernel/audit.c @@ -23,6 +23,27 @@ static unsigned chattr_class[] = { ~0U }; +int audit_classify_syscall(int abi, unsigned syscall) +{ +#ifdef CONFIG_PPC64 + extern int ppc32_classify_syscall(unsigned); + if (abi == AUDIT_ARCH_PPC) + return ppc32_classify_syscall(syscall); +#endif + 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_init(void) { #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c index ddc0a64896a2..640d4bb29321 100644 --- a/arch/powerpc/kernel/compat_audit.c +++ b/arch/powerpc/kernel/compat_audit.c @@ -20,3 +20,19 @@ unsigned ppc32_read_class[] = { #include ~0U }; + +int ppc32_classify_syscall(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 1; + } +} diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c index cde57039334c..0741d9193390 100644 --- a/arch/s390/kernel/audit.c +++ b/arch/s390/kernel/audit.c @@ -23,6 +23,27 @@ static unsigned chattr_class[] = { ~0U }; +int audit_classify_syscall(int abi, unsigned syscall) +{ +#ifdef CONFIG_COMPAT + extern int s390_classify_syscall(unsigned); + if (abi == AUDIT_ARCH_S390) + return s390_classify_syscall(syscall); +#endif + 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_init(void) { #ifdef CONFIG_COMPAT diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c index d9e5f3540d48..16d9436bfa91 100644 --- a/arch/s390/kernel/compat_audit.c +++ b/arch/s390/kernel/compat_audit.c @@ -20,3 +20,19 @@ unsigned s390_read_class[] = { #include ~0U }; + +int s390_classify_syscall(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 1; + } +} diff --git a/arch/x86_64/ia32/audit.c b/arch/x86_64/ia32/audit.c index 798501994bd9..92d7d0c8d93f 100644 --- a/arch/x86_64/ia32/audit.c +++ b/arch/x86_64/ia32/audit.c @@ -19,3 +19,19 @@ unsigned ia32_read_class[] = { #include ~0U }; + +int ia32_classify_syscall(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 1; + } +} diff --git a/arch/x86_64/kernel/audit.c b/arch/x86_64/kernel/audit.c index 36840acb6513..21f33387bef3 100644 --- a/arch/x86_64/kernel/audit.c +++ b/arch/x86_64/kernel/audit.c @@ -23,6 +23,25 @@ static unsigned chattr_class[] = { ~0U }; +int audit_classify_syscall(int abi, unsigned syscall) +{ +#ifdef CONFIG_IA32_EMULATION + extern int ia32_classify_syscall(unsigned); + if (abi == AUDIT_ARCH_I386) + return ia32_classify_syscall(syscall); +#endif + 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_init(void) { #ifdef CONFIG_IA32_EMULATION diff --git a/include/linux/audit.h b/include/linux/audit.h index 1077362a2efb..40a6c26294ae 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -181,6 +181,7 @@ #define AUDIT_EXIT 103 #define AUDIT_SUCCESS 104 /* exit >= 0; value ignored */ #define AUDIT_WATCH 105 +#define AUDIT_PERM 106 #define AUDIT_ARG0 200 #define AUDIT_ARG1 (AUDIT_ARG0+1) @@ -256,6 +257,11 @@ #define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE) #define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_PERM_EXEC 1 +#define AUDIT_PERM_WRITE 2 +#define AUDIT_PERM_READ 4 +#define AUDIT_PERM_ATTR 8 + struct audit_status { __u32 mask; /* Bit mask for valid entries */ __u32 enabled; /* 1 = enabled, 0 = disabled */ @@ -318,6 +324,7 @@ struct mqstat; #define AUDITSC_FAILURE 2 #define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) extern int __init audit_register_class(int class, unsigned *list); +extern int audit_classify_syscall(int abi, unsigned syscall); #ifdef CONFIG_AUDITSYSCALL /* These are defined in auditsc.c */ /* Public API */ diff --git a/kernel/audit.h b/kernel/audit.h index 6aa33b848cf2..a3370232a390 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -104,6 +104,7 @@ static inline int audit_hash_ino(u32 ino) return (ino & (AUDIT_INODE_BUCKETS-1)); } +extern int audit_match_class(int class, unsigned syscall); extern int audit_comparator(const u32 left, const u32 op, const u32 right); extern int audit_compare_dname_path(const char *dname, const char *path, int *dirlen); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index e4cafc11c510..a44879b0c72f 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -302,6 +302,15 @@ int __init audit_register_class(int class, unsigned *list) return 0; } +int audit_match_class(int class, unsigned syscall) +{ + if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32))) + return 0; + if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class])) + return 0; + return classes[class][AUDIT_WORD(syscall)] & AUDIT_BIT(syscall); +} + /* Common user-space to kernel rule translation. */ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) { @@ -414,6 +423,10 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) case AUDIT_ARG2: case AUDIT_ARG3: break; + case AUDIT_PERM: + if (f->val & ~15) + goto exit_free; + break; case AUDIT_INODE: err = audit_to_inode(&entry->rule, f); if (err) @@ -568,6 +581,10 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, entry->rule.buflen += f->val; entry->rule.filterkey = str; break; + case AUDIT_PERM: + if (f->val & ~15) + goto exit_free; + break; default: goto exit_free; } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index efc1b74bebf3..1bd8827a0102 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -209,6 +209,54 @@ struct audit_context { #endif }; +#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE]) +static inline int open_arg(int flags, int mask) +{ + int n = ACC_MODE(flags); + if (flags & (O_TRUNC | O_CREAT)) + n |= AUDIT_PERM_WRITE; + return n & mask; +} + +static int audit_match_perm(struct audit_context *ctx, int mask) +{ + unsigned n = ctx->major; + switch (audit_classify_syscall(ctx->arch, n)) { + case 0: /* native */ + if ((mask & AUDIT_PERM_WRITE) && + audit_match_class(AUDIT_CLASS_WRITE, n)) + return 1; + if ((mask & AUDIT_PERM_READ) && + audit_match_class(AUDIT_CLASS_READ, n)) + return 1; + if ((mask & AUDIT_PERM_ATTR) && + audit_match_class(AUDIT_CLASS_CHATTR, n)) + return 1; + return 0; + case 1: /* 32bit on biarch */ + if ((mask & AUDIT_PERM_WRITE) && + audit_match_class(AUDIT_CLASS_WRITE_32, n)) + return 1; + if ((mask & AUDIT_PERM_READ) && + audit_match_class(AUDIT_CLASS_READ_32, n)) + return 1; + if ((mask & AUDIT_PERM_ATTR) && + audit_match_class(AUDIT_CLASS_CHATTR_32, n)) + return 1; + return 0; + case 2: /* open */ + return mask & ACC_MODE(ctx->argv[1]); + case 3: /* openat */ + return mask & ACC_MODE(ctx->argv[2]); + case 4: /* socketcall */ + return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND); + case 5: /* execve */ + return mask & AUDIT_PERM_EXEC; + default: + return 0; + } +} + /* Determine if any context name data matches a rule's watch data */ /* Compare a task_struct with an audit_rule. Return 1 on match, 0 * otherwise. */ @@ -397,6 +445,9 @@ static int audit_filter_rules(struct task_struct *tsk, /* ignore this field for filtering */ result = 1; break; + case AUDIT_PERM: + result = audit_match_perm(ctx, f->val); + break; } if (!result)