diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2006-08-31 19:26:40 -0400 | 
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2006-09-11 13:32:30 -0400 | 
| commit | 55669bfa141b488be865341ed12e188967d11308 (patch) | |
| tree | efeec37a93f46c48937eb849c083da9a42ed3709 | |
| parent | dc104fb3231f11e95b5a0f09ae3ab27a8fd5b2e8 (diff) | |
| download | olio-linux-3.10-55669bfa141b488be865341ed12e188967d11308.tar.xz olio-linux-3.10-55669bfa141b488be865341ed12e188967d11308.zip  | |
[PATCH] audit: AUDIT_PERM support
add support for AUDIT_PERM predicate
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | arch/i386/kernel/audit.c | 16 | ||||
| -rw-r--r-- | arch/ia64/ia32/audit.c | 16 | ||||
| -rw-r--r-- | arch/ia64/kernel/audit.c | 19 | ||||
| -rw-r--r-- | arch/powerpc/kernel/audit.c | 21 | ||||
| -rw-r--r-- | arch/powerpc/kernel/compat_audit.c | 16 | ||||
| -rw-r--r-- | arch/s390/kernel/audit.c | 21 | ||||
| -rw-r--r-- | arch/s390/kernel/compat_audit.c | 16 | ||||
| -rw-r--r-- | arch/x86_64/ia32/audit.c | 16 | ||||
| -rw-r--r-- | arch/x86_64/kernel/audit.c | 19 | ||||
| -rw-r--r-- | include/linux/audit.h | 7 | ||||
| -rw-r--r-- | kernel/audit.h | 1 | ||||
| -rw-r--r-- | kernel/auditfilter.c | 17 | ||||
| -rw-r--r-- | kernel/auditsc.c | 51 | 
13 files changed, 236 insertions, 0 deletions
diff --git a/arch/i386/kernel/audit.c b/arch/i386/kernel/audit.c index 28bbc46f75c..3b97cff4154 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 798501994bd..92d7d0c8d93 100644 --- a/arch/ia64/ia32/audit.c +++ b/arch/ia64/ia32/audit.c @@ -19,3 +19,19 @@ unsigned ia32_read_class[] = {  #include <asm-generic/audit_read.h>  ~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 99488cdbf5c..04682555a28 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 24a65e3724e..7fe5e6300e9 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 ddc0a64896a..640d4bb2932 100644 --- a/arch/powerpc/kernel/compat_audit.c +++ b/arch/powerpc/kernel/compat_audit.c @@ -20,3 +20,19 @@ unsigned ppc32_read_class[] = {  #include <asm-generic/audit_read.h>  ~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 cde57039334..0741d919339 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 d9e5f3540d4..16d9436bfa9 100644 --- a/arch/s390/kernel/compat_audit.c +++ b/arch/s390/kernel/compat_audit.c @@ -20,3 +20,19 @@ unsigned s390_read_class[] = {  #include <asm-generic/audit_read.h>  ~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 798501994bd..92d7d0c8d93 100644 --- a/arch/x86_64/ia32/audit.c +++ b/arch/x86_64/ia32/audit.c @@ -19,3 +19,19 @@ unsigned ia32_read_class[] = {  #include <asm-generic/audit_read.h>  ~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 36840acb651..21f33387bef 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 1077362a2ef..40a6c26294a 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 6aa33b848cf..a3370232a39 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 e4cafc11c51..a44879b0c72 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 efc1b74bebf..1bd8827a010 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)  |