diff options
Diffstat (limited to 'kernel/auditsc.c')
| -rw-r--r-- | kernel/auditsc.c | 407 | 
1 files changed, 40 insertions, 367 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index c68229411a7c..3c8a601324a2 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -76,11 +76,6 @@  #define AUDITSC_SUCCESS 1  #define AUDITSC_FAILURE 2 -/* AUDIT_NAMES is the number of slots we reserve in the audit_context - * for saving names from getname().  If we get more names we will allocate - * a name dynamically and also add those to the list anchored by names_list. */ -#define AUDIT_NAMES	5 -  /* no execve audit message should be longer than this (userspace limits) */  #define MAX_EXECVE_AUDIT_LEN 7500 @@ -90,44 +85,6 @@ int audit_n_rules;  /* determines whether we collect data for signals sent */  int audit_signals; -struct audit_cap_data { -	kernel_cap_t		permitted; -	kernel_cap_t		inheritable; -	union { -		unsigned int	fE;		/* effective bit of a file capability */ -		kernel_cap_t	effective;	/* effective set of a process */ -	}; -}; - -/* When fs/namei.c:getname() is called, we store the pointer in name and - * we don't let putname() free it (instead we free all of the saved - * pointers at syscall exit time). - * - * Further, in fs/namei.c:path_lookup() we store the inode and device. - */ -struct audit_names { -	struct list_head	list;		/* audit_context->names_list */ -	struct filename	*name; -	unsigned long		ino; -	dev_t			dev; -	umode_t			mode; -	kuid_t			uid; -	kgid_t			gid; -	dev_t			rdev; -	u32			osid; -	struct audit_cap_data	 fcap; -	unsigned int		fcap_ver; -	int			name_len;	/* number of name's characters to log */ -	unsigned char		type;		/* record type */ -	bool			name_put;	/* call __putname() for this name */ -	/* -	 * This was an allocated audit_names and not from the array of -	 * names allocated in the task audit context.  Thus this name -	 * should be freed on syscall exit -	 */ -	bool			should_free; -}; -  struct audit_aux_data {  	struct audit_aux_data	*next;  	int			type; @@ -175,106 +132,6 @@ struct audit_tree_refs {  	struct audit_chunk *c[31];  }; -/* The per-task audit context. */ -struct audit_context { -	int		    dummy;	/* must be the first element */ -	int		    in_syscall;	/* 1 if task is in a syscall */ -	enum audit_state    state, current_state; -	unsigned int	    serial;     /* serial number for record */ -	int		    major;      /* syscall number */ -	struct timespec	    ctime;      /* time of syscall entry */ -	unsigned long	    argv[4];    /* syscall arguments */ -	long		    return_code;/* syscall return code */ -	u64		    prio; -	int		    return_valid; /* return code is valid */ -	/* -	 * The names_list is the list of all audit_names collected during this -	 * syscall.  The first AUDIT_NAMES entries in the names_list will -	 * actually be from the preallocated_names array for performance -	 * reasons.  Except during allocation they should never be referenced -	 * through the preallocated_names array and should only be found/used -	 * by running the names_list. -	 */ -	struct audit_names  preallocated_names[AUDIT_NAMES]; -	int		    name_count; /* total records in names_list */ -	struct list_head    names_list;	/* anchor for struct audit_names->list */ -	char *		    filterkey;	/* key for rule that triggered record */ -	struct path	    pwd; -	struct audit_aux_data *aux; -	struct audit_aux_data *aux_pids; -	struct sockaddr_storage *sockaddr; -	size_t sockaddr_len; -				/* Save things to print about task_struct */ -	pid_t		    pid, ppid; -	kuid_t		    uid, euid, suid, fsuid; -	kgid_t		    gid, egid, sgid, fsgid; -	unsigned long	    personality; -	int		    arch; - -	pid_t		    target_pid; -	kuid_t		    target_auid; -	kuid_t		    target_uid; -	unsigned int	    target_sessionid; -	u32		    target_sid; -	char		    target_comm[TASK_COMM_LEN]; - -	struct audit_tree_refs *trees, *first_trees; -	struct list_head killed_trees; -	int tree_count; - -	int type; -	union { -		struct { -			int nargs; -			long args[6]; -		} socketcall; -		struct { -			kuid_t			uid; -			kgid_t			gid; -			umode_t			mode; -			u32			osid; -			int			has_perm; -			uid_t			perm_uid; -			gid_t			perm_gid; -			umode_t			perm_mode; -			unsigned long		qbytes; -		} ipc; -		struct { -			mqd_t			mqdes; -			struct mq_attr 		mqstat; -		} mq_getsetattr; -		struct { -			mqd_t			mqdes; -			int			sigev_signo; -		} mq_notify; -		struct { -			mqd_t			mqdes; -			size_t			msg_len; -			unsigned int		msg_prio; -			struct timespec		abs_timeout; -		} mq_sendrecv; -		struct { -			int			oflag; -			umode_t			mode; -			struct mq_attr		attr; -		} mq_open; -		struct { -			pid_t			pid; -			struct audit_cap_data	cap; -		} capset; -		struct { -			int			fd; -			int			flags; -		} mmap; -	}; -	int fds[2]; - -#if AUDIT_DEBUG -	int		    put_count; -	int		    ino_count; -#endif -}; -  static inline int open_arg(int flags, int mask)  {  	int n = ACC_MODE(flags); @@ -633,9 +490,23 @@ static int audit_filter_rules(struct task_struct *tsk,  			break;  		case AUDIT_GID:  			result = audit_gid_comparator(cred->gid, f->op, f->gid); +			if (f->op == Audit_equal) { +				if (!result) +					result = in_group_p(f->gid); +			} else if (f->op == Audit_not_equal) { +				if (result) +					result = !in_group_p(f->gid); +			}  			break;  		case AUDIT_EGID:  			result = audit_gid_comparator(cred->egid, f->op, f->gid); +			if (f->op == Audit_equal) { +				if (!result) +					result = in_egroup_p(f->gid); +			} else if (f->op == Audit_not_equal) { +				if (result) +					result = !in_egroup_p(f->gid); +			}  			break;  		case AUDIT_SGID:  			result = audit_gid_comparator(cred->sgid, f->op, f->gid); @@ -742,6 +613,9 @@ static int audit_filter_rules(struct task_struct *tsk,  			if (ctx)  				result = audit_uid_comparator(tsk->loginuid, f->op, f->uid);  			break; +		case AUDIT_LOGINUID_SET: +			result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val); +			break;  		case AUDIT_SUBJ_USER:  		case AUDIT_SUBJ_ROLE:  		case AUDIT_SUBJ_TYPE: @@ -987,6 +861,8 @@ static inline void audit_free_names(struct audit_context *context)  #if AUDIT_DEBUG == 2  	if (context->put_count + context->ino_count != context->name_count) { +		int i = 0; +  		printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"  		       " name_count=%d put_count=%d"  		       " ino_count=%d [NOT freeing]\n", @@ -995,7 +871,7 @@ static inline void audit_free_names(struct audit_context *context)  		       context->name_count, context->put_count,  		       context->ino_count);  		list_for_each_entry(n, &context->names_list, list) { -			printk(KERN_ERR "names[%d] = %p = %s\n", i, +			printk(KERN_ERR "names[%d] = %p = %s\n", i++,  			       n->name, n->name->name ?: "(null)");  		}  		dump_stack(); @@ -1010,7 +886,7 @@ static inline void audit_free_names(struct audit_context *context)  	list_for_each_entry_safe(n, next, &context->names_list, list) {  		list_del(&n->list);  		if (n->name && n->name_put) -			__putname(n->name); +			final_putname(n->name);  		if (n->should_free)  			kfree(n);  	} @@ -1093,88 +969,6 @@ static inline void audit_free_context(struct audit_context *context)  	kfree(context);  } -void audit_log_task_context(struct audit_buffer *ab) -{ -	char *ctx = NULL; -	unsigned len; -	int error; -	u32 sid; - -	security_task_getsecid(current, &sid); -	if (!sid) -		return; - -	error = security_secid_to_secctx(sid, &ctx, &len); -	if (error) { -		if (error != -EINVAL) -			goto error_path; -		return; -	} - -	audit_log_format(ab, " subj=%s", ctx); -	security_release_secctx(ctx, len); -	return; - -error_path: -	audit_panic("error in audit_log_task_context"); -	return; -} - -EXPORT_SYMBOL(audit_log_task_context); - -void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) -{ -	const struct cred *cred; -	char name[sizeof(tsk->comm)]; -	struct mm_struct *mm = tsk->mm; -	char *tty; - -	if (!ab) -		return; - -	/* tsk == current */ -	cred = current_cred(); - -	spin_lock_irq(&tsk->sighand->siglock); -	if (tsk->signal && tsk->signal->tty) -		tty = tsk->signal->tty->name; -	else -		tty = "(none)"; -	spin_unlock_irq(&tsk->sighand->siglock); - - -	audit_log_format(ab, -			 " ppid=%ld pid=%d auid=%u uid=%u gid=%u" -			 " euid=%u suid=%u fsuid=%u" -			 " egid=%u sgid=%u fsgid=%u ses=%u tty=%s", -			 sys_getppid(), -			 tsk->pid, -			 from_kuid(&init_user_ns, tsk->loginuid), -			 from_kuid(&init_user_ns, cred->uid), -			 from_kgid(&init_user_ns, cred->gid), -			 from_kuid(&init_user_ns, cred->euid), -			 from_kuid(&init_user_ns, cred->suid), -			 from_kuid(&init_user_ns, cred->fsuid), -			 from_kgid(&init_user_ns, cred->egid), -			 from_kgid(&init_user_ns, cred->sgid), -			 from_kgid(&init_user_ns, cred->fsgid), -			 tsk->sessionid, tty); - -	get_task_comm(name, tsk); -	audit_log_format(ab, " comm="); -	audit_log_untrustedstring(ab, name); - -	if (mm) { -		down_read(&mm->mmap_sem); -		if (mm->exe_file) -			audit_log_d_path(ab, " exe=", &mm->exe_file->f_path); -		up_read(&mm->mmap_sem); -	} -	audit_log_task_context(ab); -} - -EXPORT_SYMBOL(audit_log_task_info); -  static int audit_log_pid_context(struct audit_context *context, pid_t pid,  				 kuid_t auid, kuid_t uid, unsigned int sessionid,  				 u32 sid, char *comm) @@ -1191,12 +985,14 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,  	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,  			 from_kuid(&init_user_ns, auid),  			 from_kuid(&init_user_ns, uid), sessionid); -	if (security_secid_to_secctx(sid, &ctx, &len)) { -		audit_log_format(ab, " obj=(none)"); -		rc = 1; -	} else { -		audit_log_format(ab, " obj=%s", ctx); -		security_release_secctx(ctx, len); +	if (sid) { +		if (security_secid_to_secctx(sid, &ctx, &len)) { +			audit_log_format(ab, " obj=(none)"); +			rc = 1; +		} else { +			audit_log_format(ab, " obj=%s", ctx); +			security_release_secctx(ctx, len); +		}  	}  	audit_log_format(ab, " ocomm=");  	audit_log_untrustedstring(ab, comm); @@ -1390,35 +1186,6 @@ static void audit_log_execve_info(struct audit_context *context,  	kfree(buf);  } -static void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) -{ -	int i; - -	audit_log_format(ab, " %s=", prefix); -	CAP_FOR_EACH_U32(i) { -		audit_log_format(ab, "%08x", cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]); -	} -} - -static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) -{ -	kernel_cap_t *perm = &name->fcap.permitted; -	kernel_cap_t *inh = &name->fcap.inheritable; -	int log = 0; - -	if (!cap_isclear(*perm)) { -		audit_log_cap(ab, "cap_fp", perm); -		log = 1; -	} -	if (!cap_isclear(*inh)) { -		audit_log_cap(ab, "cap_fi", inh); -		log = 1; -	} - -	if (log) -		audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver); -} -  static void show_special(struct audit_context *context, int *call_panic)  {  	struct audit_buffer *ab; @@ -1516,68 +1283,6 @@ static void show_special(struct audit_context *context, int *call_panic)  	audit_log_end(ab);  } -static void audit_log_name(struct audit_context *context, struct audit_names *n, -			   int record_num, int *call_panic) -{ -	struct audit_buffer *ab; -	ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); -	if (!ab) -		return; /* audit_panic has been called */ - -	audit_log_format(ab, "item=%d", record_num); - -	if (n->name) { -		switch (n->name_len) { -		case AUDIT_NAME_FULL: -			/* log the full path */ -			audit_log_format(ab, " name="); -			audit_log_untrustedstring(ab, n->name->name); -			break; -		case 0: -			/* name was specified as a relative path and the -			 * directory component is the cwd */ -			audit_log_d_path(ab, " name=", &context->pwd); -			break; -		default: -			/* log the name's directory component */ -			audit_log_format(ab, " name="); -			audit_log_n_untrustedstring(ab, n->name->name, -						    n->name_len); -		} -	} else -		audit_log_format(ab, " name=(null)"); - -	if (n->ino != (unsigned long)-1) { -		audit_log_format(ab, " inode=%lu" -				 " dev=%02x:%02x mode=%#ho" -				 " ouid=%u ogid=%u rdev=%02x:%02x", -				 n->ino, -				 MAJOR(n->dev), -				 MINOR(n->dev), -				 n->mode, -				 from_kuid(&init_user_ns, n->uid), -				 from_kgid(&init_user_ns, n->gid), -				 MAJOR(n->rdev), -				 MINOR(n->rdev)); -	} -	if (n->osid != 0) { -		char *ctx = NULL; -		u32 len; -		if (security_secid_to_secctx( -			n->osid, &ctx, &len)) { -			audit_log_format(ab, " osid=%u", n->osid); -			*call_panic = 2; -		} else { -			audit_log_format(ab, " obj=%s", ctx); -			security_release_secctx(ctx, len); -		} -	} - -	audit_log_fcaps(ab, n); - -	audit_log_end(ab); -} -  static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)  {  	int i, call_panic = 0; @@ -1695,7 +1400,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts  	i = 0;  	list_for_each_entry(n, &context->names_list, list) -		audit_log_name(context, n, i++, &call_panic); +		audit_log_name(context, n, NULL, i++, &call_panic);  	/* Send end of event record to help user space know we are finished */  	ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); @@ -2030,18 +1735,18 @@ void audit_putname(struct filename *name)  	BUG_ON(!context);  	if (!context->in_syscall) {  #if AUDIT_DEBUG == 2 -		printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", +		printk(KERN_ERR "%s:%d(:%d): final_putname(%p)\n",  		       __FILE__, __LINE__, context->serial, name);  		if (context->name_count) {  			struct audit_names *n; -			int i; +			int i = 0;  			list_for_each_entry(n, &context->names_list, list) -				printk(KERN_ERR "name[%d] = %p = %s\n", i, +				printk(KERN_ERR "name[%d] = %p = %s\n", i++,  				       n->name, n->name->name ?: "(null)");  			}  #endif -		__putname(name); +		final_putname(name);  	}  #if AUDIT_DEBUG  	else { @@ -2060,41 +1765,6 @@ void audit_putname(struct filename *name)  #endif  } -static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) -{ -	struct cpu_vfs_cap_data caps; -	int rc; - -	if (!dentry) -		return 0; - -	rc = get_vfs_caps_from_disk(dentry, &caps); -	if (rc) -		return rc; - -	name->fcap.permitted = caps.permitted; -	name->fcap.inheritable = caps.inheritable; -	name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); -	name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT; - -	return 0; -} - - -/* Copy inode data into an audit_names. */ -static void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, -			     const struct inode *inode) -{ -	name->ino   = inode->i_ino; -	name->dev   = inode->i_sb->s_dev; -	name->mode  = inode->i_mode; -	name->uid   = inode->i_uid; -	name->gid   = inode->i_gid; -	name->rdev  = inode->i_rdev; -	security_inode_getsecid(inode, &name->osid); -	audit_copy_fcaps(name, dentry); -} -  /**   * __audit_inode - store the inode and device from a lookup   * @name: name being audited @@ -2303,7 +1973,7 @@ int audit_set_loginuid(kuid_t loginuid)  	unsigned int sessionid;  #ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE -	if (uid_valid(task->loginuid)) +	if (audit_loginuid_set(task))  		return -EPERM;  #else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */  	if (!capable(CAP_AUDIT_CONTROL)) @@ -2471,17 +2141,20 @@ int __audit_bprm(struct linux_binprm *bprm)  /**   * audit_socketcall - record audit data for sys_socketcall - * @nargs: number of args + * @nargs: number of args, which should not be more than AUDITSC_ARGS.   * @args: args array   *   */ -void __audit_socketcall(int nargs, unsigned long *args) +int __audit_socketcall(int nargs, unsigned long *args)  {  	struct audit_context *context = current->audit_context; +	if (nargs <= 0 || nargs > AUDITSC_ARGS || !args) +		return -EINVAL;  	context->type = AUDIT_SOCKETCALL;  	context->socketcall.nargs = nargs;  	memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long)); +	return 0;  }  /**  |