[PATCH] audit: AUDIT_PERM support
add support for AUDIT_PERM predicate Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
					parent
					
						
							
								dc104fb323
							
						
					
				
			
			
				commit
				
					
						55669bfa14
					
				
			
		
					 13 changed files with 236 additions and 0 deletions
				
			
		|  | @ -23,6 +23,22 @@ static unsigned chattr_class[] = { | ||||||
| ~0U | ~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) | static int __init audit_classes_init(void) | ||||||
| { | { | ||||||
| 	audit_register_class(AUDIT_CLASS_WRITE, write_class); | 	audit_register_class(AUDIT_CLASS_WRITE, write_class); | ||||||
|  |  | ||||||
|  | @ -19,3 +19,19 @@ unsigned ia32_read_class[] = { | ||||||
| #include <asm-generic/audit_read.h> | #include <asm-generic/audit_read.h> | ||||||
| ~0U | ~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; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -23,6 +23,25 @@ static unsigned chattr_class[] = { | ||||||
| ~0U | ~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) | static int __init audit_classes_init(void) | ||||||
| { | { | ||||||
| #ifdef CONFIG_IA32_SUPPORT | #ifdef CONFIG_IA32_SUPPORT | ||||||
|  |  | ||||||
|  | @ -23,6 +23,27 @@ static unsigned chattr_class[] = { | ||||||
| ~0U | ~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) | static int __init audit_classes_init(void) | ||||||
| { | { | ||||||
| #ifdef CONFIG_PPC64 | #ifdef CONFIG_PPC64 | ||||||
|  |  | ||||||
|  | @ -20,3 +20,19 @@ unsigned ppc32_read_class[] = { | ||||||
| #include <asm-generic/audit_read.h> | #include <asm-generic/audit_read.h> | ||||||
| ~0U | ~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; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -23,6 +23,27 @@ static unsigned chattr_class[] = { | ||||||
| ~0U | ~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) | static int __init audit_classes_init(void) | ||||||
| { | { | ||||||
| #ifdef CONFIG_COMPAT | #ifdef CONFIG_COMPAT | ||||||
|  |  | ||||||
|  | @ -20,3 +20,19 @@ unsigned s390_read_class[] = { | ||||||
| #include <asm-generic/audit_read.h> | #include <asm-generic/audit_read.h> | ||||||
| ~0U | ~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; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -19,3 +19,19 @@ unsigned ia32_read_class[] = { | ||||||
| #include <asm-generic/audit_read.h> | #include <asm-generic/audit_read.h> | ||||||
| ~0U | ~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; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -23,6 +23,25 @@ static unsigned chattr_class[] = { | ||||||
| ~0U | ~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) | static int __init audit_classes_init(void) | ||||||
| { | { | ||||||
| #ifdef CONFIG_IA32_EMULATION | #ifdef CONFIG_IA32_EMULATION | ||||||
|  |  | ||||||
|  | @ -181,6 +181,7 @@ | ||||||
| #define AUDIT_EXIT	103 | #define AUDIT_EXIT	103 | ||||||
| #define AUDIT_SUCCESS   104	/* exit >= 0; value ignored */ | #define AUDIT_SUCCESS   104	/* exit >= 0; value ignored */ | ||||||
| #define AUDIT_WATCH	105 | #define AUDIT_WATCH	105 | ||||||
|  | #define AUDIT_PERM	106 | ||||||
| 
 | 
 | ||||||
| #define AUDIT_ARG0      200 | #define AUDIT_ARG0      200 | ||||||
| #define AUDIT_ARG1      (AUDIT_ARG0+1) | #define AUDIT_ARG1      (AUDIT_ARG0+1) | ||||||
|  | @ -256,6 +257,11 @@ | ||||||
| #define AUDIT_ARCH_V850		(EM_V850|__AUDIT_ARCH_LE) | #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_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 { | struct audit_status { | ||||||
| 	__u32		mask;		/* Bit mask for valid entries */ | 	__u32		mask;		/* Bit mask for valid entries */ | ||||||
| 	__u32		enabled;	/* 1 = enabled, 0 = disabled */ | 	__u32		enabled;	/* 1 = enabled, 0 = disabled */ | ||||||
|  | @ -318,6 +324,7 @@ struct mqstat; | ||||||
| #define AUDITSC_FAILURE 2 | #define AUDITSC_FAILURE 2 | ||||||
| #define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) | #define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) | ||||||
| extern int __init audit_register_class(int class, unsigned *list); | extern int __init audit_register_class(int class, unsigned *list); | ||||||
|  | extern int audit_classify_syscall(int abi, unsigned syscall); | ||||||
| #ifdef CONFIG_AUDITSYSCALL | #ifdef CONFIG_AUDITSYSCALL | ||||||
| /* These are defined in auditsc.c */ | /* These are defined in auditsc.c */ | ||||||
| 				/* Public API */ | 				/* Public API */ | ||||||
|  |  | ||||||
|  | @ -104,6 +104,7 @@ static inline int audit_hash_ino(u32 ino) | ||||||
| 	return (ino & (AUDIT_INODE_BUCKETS-1)); | 	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_comparator(const u32 left, const u32 op, const u32 right); | ||||||
| extern int audit_compare_dname_path(const char *dname, const char *path, | extern int audit_compare_dname_path(const char *dname, const char *path, | ||||||
| 				    int *dirlen); | 				    int *dirlen); | ||||||
|  |  | ||||||
|  | @ -302,6 +302,15 @@ int __init audit_register_class(int class, unsigned *list) | ||||||
| 	return 0; | 	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. */ | /* Common user-space to kernel rule translation. */ | ||||||
| static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) | 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_ARG2: | ||||||
| 		case AUDIT_ARG3: | 		case AUDIT_ARG3: | ||||||
| 			break; | 			break; | ||||||
|  | 		case AUDIT_PERM: | ||||||
|  | 			if (f->val & ~15) | ||||||
|  | 				goto exit_free; | ||||||
|  | 			break; | ||||||
| 		case AUDIT_INODE: | 		case AUDIT_INODE: | ||||||
| 			err = audit_to_inode(&entry->rule, f); | 			err = audit_to_inode(&entry->rule, f); | ||||||
| 			if (err) | 			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.buflen += f->val; | ||||||
| 			entry->rule.filterkey = str; | 			entry->rule.filterkey = str; | ||||||
| 			break; | 			break; | ||||||
|  | 		case AUDIT_PERM: | ||||||
|  | 			if (f->val & ~15) | ||||||
|  | 				goto exit_free; | ||||||
|  | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			goto exit_free; | 			goto exit_free; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -209,6 +209,54 @@ struct audit_context { | ||||||
| #endif | #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 */ | /* 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
 | /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
 | ||||||
|  * otherwise. */ |  * otherwise. */ | ||||||
|  | @ -397,6 +445,9 @@ static int audit_filter_rules(struct task_struct *tsk, | ||||||
| 			/* ignore this field for filtering */ | 			/* ignore this field for filtering */ | ||||||
| 			result = 1; | 			result = 1; | ||||||
| 			break; | 			break; | ||||||
|  | 		case AUDIT_PERM: | ||||||
|  | 			result = audit_match_perm(ctx, f->val); | ||||||
|  | 			break; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!result) | 		if (!result) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Al Viro
				Al Viro