Merge git://git.infradead.org/users/eparis/audit
Pull audit updates from Eric Paris: "Nothing amazing. Formatting, small bug fixes, couple of fixes where we didn't get records due to some old VFS changes, and a change to how we collect execve info..." Fixed conflict in fs/exec.c as per Eric and linux-next. * git://git.infradead.org/users/eparis/audit: (28 commits) audit: fix type of sessionid in audit_set_loginuid() audit: call audit_bprm() only once to add AUDIT_EXECVE information audit: move audit_aux_data_execve contents into audit_context union audit: remove unused envc member of audit_aux_data_execve audit: Kill the unused struct audit_aux_data_capset audit: do not reject all AUDIT_INODE filter types audit: suppress stock memalloc failure warnings since already managed audit: log the audit_names record type audit: add child record before the create to handle case where create fails audit: use given values in tty_audit enable api audit: use nlmsg_len() to get message payload length audit: use memset instead of trying to initialize field by field audit: fix info leak in AUDIT_GET requests audit: update AUDIT_INODE filter rule to comparator function audit: audit feature to set loginuid immutable audit: audit feature to only allow unsetting the loginuid audit: allow unsetting the loginuid (with priv) audit: remove CONFIG_AUDIT_LOGINUID_IMMUTABLE audit: loginuid functions coding style selinux: apply selinux checks on new audit message types ...
This commit is contained in:
		
				commit
				
					
						3eaded86ac
					
				
			
		
					 12 changed files with 259 additions and 113 deletions
				
			
		| 
						 | 
					@ -1380,10 +1380,6 @@ int search_binary_handler(struct linux_binprm *bprm)
 | 
				
			||||||
	if (retval)
 | 
						if (retval)
 | 
				
			||||||
		return retval;
 | 
							return retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retval = audit_bprm(bprm);
 | 
					 | 
				
			||||||
	if (retval)
 | 
					 | 
				
			||||||
		return retval;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	retval = -ENOENT;
 | 
						retval = -ENOENT;
 | 
				
			||||||
 retry:
 | 
					 retry:
 | 
				
			||||||
	read_lock(&binfmt_lock);
 | 
						read_lock(&binfmt_lock);
 | 
				
			||||||
| 
						 | 
					@ -1431,6 +1427,7 @@ static int exec_binprm(struct linux_binprm *bprm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = search_binary_handler(bprm);
 | 
						ret = search_binary_handler(bprm);
 | 
				
			||||||
	if (ret >= 0) {
 | 
						if (ret >= 0) {
 | 
				
			||||||
 | 
							audit_bprm(bprm);
 | 
				
			||||||
		trace_sched_process_exec(current, old_pid, bprm);
 | 
							trace_sched_process_exec(current, old_pid, bprm);
 | 
				
			||||||
		ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
 | 
							ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
 | 
				
			||||||
		current->did_exec = 1;
 | 
							current->did_exec = 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2435,6 +2435,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline int may_create(struct inode *dir, struct dentry *child)
 | 
					static inline int may_create(struct inode *dir, struct dentry *child)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
 | 
				
			||||||
	if (child->d_inode)
 | 
						if (child->d_inode)
 | 
				
			||||||
		return -EEXIST;
 | 
							return -EEXIST;
 | 
				
			||||||
	if (IS_DEADDIR(dir))
 | 
						if (IS_DEADDIR(dir))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1151,10 +1151,16 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
 | 
				
			||||||
		goto out_free_page;
 | 
							goto out_free_page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
 | 
					
 | 
				
			||||||
	if (!uid_valid(kloginuid)) {
 | 
						/* is userspace tring to explicitly UNSET the loginuid? */
 | 
				
			||||||
		length = -EINVAL;
 | 
						if (loginuid == AUDIT_UID_UNSET) {
 | 
				
			||||||
		goto out_free_page;
 | 
							kloginuid = INVALID_UID;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
 | 
				
			||||||
 | 
							if (!uid_valid(kloginuid)) {
 | 
				
			||||||
 | 
								length = -EINVAL;
 | 
				
			||||||
 | 
								goto out_free_page;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	length = audit_set_loginuid(kloginuid);
 | 
						length = audit_set_loginuid(kloginuid);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,6 +73,8 @@ struct audit_field {
 | 
				
			||||||
	void				*lsm_rule;
 | 
						void				*lsm_rule;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int is_audit_feature_set(int which);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
					extern int audit_classify_syscall(int abi, unsigned syscall);
 | 
				
			||||||
extern int audit_classify_arch(int arch);
 | 
					extern int audit_classify_arch(int arch);
 | 
				
			||||||
| 
						 | 
					@ -207,7 +209,7 @@ static inline int audit_get_sessionid(struct task_struct *tsk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
 | 
					extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
 | 
				
			||||||
extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
 | 
					extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
 | 
				
			||||||
extern int __audit_bprm(struct linux_binprm *bprm);
 | 
					extern void __audit_bprm(struct linux_binprm *bprm);
 | 
				
			||||||
extern int __audit_socketcall(int nargs, unsigned long *args);
 | 
					extern int __audit_socketcall(int nargs, unsigned long *args);
 | 
				
			||||||
extern int __audit_sockaddr(int len, void *addr);
 | 
					extern int __audit_sockaddr(int len, void *addr);
 | 
				
			||||||
extern void __audit_fd_pair(int fd1, int fd2);
 | 
					extern void __audit_fd_pair(int fd1, int fd2);
 | 
				
			||||||
| 
						 | 
					@ -236,11 +238,10 @@ static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid
 | 
				
			||||||
	if (unlikely(!audit_dummy_context()))
 | 
						if (unlikely(!audit_dummy_context()))
 | 
				
			||||||
		__audit_ipc_set_perm(qbytes, uid, gid, mode);
 | 
							__audit_ipc_set_perm(qbytes, uid, gid, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline int audit_bprm(struct linux_binprm *bprm)
 | 
					static inline void audit_bprm(struct linux_binprm *bprm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (unlikely(!audit_dummy_context()))
 | 
						if (unlikely(!audit_dummy_context()))
 | 
				
			||||||
		return __audit_bprm(bprm);
 | 
							__audit_bprm(bprm);
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline int audit_socketcall(int nargs, unsigned long *args)
 | 
					static inline int audit_socketcall(int nargs, unsigned long *args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -367,10 +368,8 @@ static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
 | 
				
			||||||
static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid,
 | 
					static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid,
 | 
				
			||||||
					gid_t gid, umode_t mode)
 | 
										gid_t gid, umode_t mode)
 | 
				
			||||||
{ }
 | 
					{ }
 | 
				
			||||||
static inline int audit_bprm(struct linux_binprm *bprm)
 | 
					static inline void audit_bprm(struct linux_binprm *bprm)
 | 
				
			||||||
{
 | 
					{ }
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static inline int audit_socketcall(int nargs, unsigned long *args)
 | 
					static inline int audit_socketcall(int nargs, unsigned long *args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +68,9 @@
 | 
				
			||||||
#define AUDIT_MAKE_EQUIV	1015	/* Append to watched tree */
 | 
					#define AUDIT_MAKE_EQUIV	1015	/* Append to watched tree */
 | 
				
			||||||
#define AUDIT_TTY_GET		1016	/* Get TTY auditing status */
 | 
					#define AUDIT_TTY_GET		1016	/* Get TTY auditing status */
 | 
				
			||||||
#define AUDIT_TTY_SET		1017	/* Set TTY auditing status */
 | 
					#define AUDIT_TTY_SET		1017	/* Set TTY auditing status */
 | 
				
			||||||
 | 
					#define AUDIT_SET_FEATURE	1018	/* Turn an audit feature on or off */
 | 
				
			||||||
 | 
					#define AUDIT_GET_FEATURE	1019	/* Get which features are enabled */
 | 
				
			||||||
 | 
					#define AUDIT_FEATURE_CHANGE	1020	/* audit log listing feature changes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AUDIT_FIRST_USER_MSG	1100	/* Userspace messages mostly uninteresting to kernel */
 | 
					#define AUDIT_FIRST_USER_MSG	1100	/* Userspace messages mostly uninteresting to kernel */
 | 
				
			||||||
#define AUDIT_USER_AVC		1107	/* We filter this differently */
 | 
					#define AUDIT_USER_AVC		1107	/* We filter this differently */
 | 
				
			||||||
| 
						 | 
					@ -357,6 +360,12 @@ enum {
 | 
				
			||||||
#define AUDIT_PERM_READ		4
 | 
					#define AUDIT_PERM_READ		4
 | 
				
			||||||
#define AUDIT_PERM_ATTR		8
 | 
					#define AUDIT_PERM_ATTR		8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MAX_AUDIT_MESSAGE_LENGTH is set in audit:lib/libaudit.h as:
 | 
				
			||||||
 | 
					 * 8970 // PATH_MAX*2+CONTEXT_SIZE*2+11+256+1
 | 
				
			||||||
 | 
					 * max header+body+tailer: 44 + 29 + 32 + 262 + 7 + pad
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define AUDIT_MESSAGE_TEXT_MAX	8560
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 */
 | 
				
			||||||
| 
						 | 
					@ -368,11 +377,28 @@ struct audit_status {
 | 
				
			||||||
	__u32		backlog;	/* messages waiting in queue */
 | 
						__u32		backlog;	/* messages waiting in queue */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct audit_features {
 | 
				
			||||||
 | 
					#define AUDIT_FEATURE_VERSION	1
 | 
				
			||||||
 | 
						__u32	vers;
 | 
				
			||||||
 | 
						__u32	mask;		/* which bits we are dealing with */
 | 
				
			||||||
 | 
						__u32	features;	/* which feature to enable/disable */
 | 
				
			||||||
 | 
						__u32	lock;		/* which features to lock */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AUDIT_FEATURE_ONLY_UNSET_LOGINUID	0
 | 
				
			||||||
 | 
					#define AUDIT_FEATURE_LOGINUID_IMMUTABLE	1
 | 
				
			||||||
 | 
					#define AUDIT_LAST_FEATURE			AUDIT_FEATURE_LOGINUID_IMMUTABLE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define audit_feature_valid(x)		((x) >= 0 && (x) <= AUDIT_LAST_FEATURE)
 | 
				
			||||||
 | 
					#define AUDIT_FEATURE_TO_MASK(x)	(1 << ((x) & 31)) /* mask for __u32 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct audit_tty_status {
 | 
					struct audit_tty_status {
 | 
				
			||||||
	__u32		enabled;	/* 1 = enabled, 0 = disabled */
 | 
						__u32		enabled;	/* 1 = enabled, 0 = disabled */
 | 
				
			||||||
	__u32		log_passwd;	/* 1 = enabled, 0 = disabled */
 | 
						__u32		log_passwd;	/* 1 = enabled, 0 = disabled */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AUDIT_UID_UNSET (unsigned int)-1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* audit_rule_data supports filter rules with both integer and string
 | 
					/* audit_rule_data supports filter rules with both integer and string
 | 
				
			||||||
 * fields.  It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
 | 
					 * fields.  It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
 | 
				
			||||||
 * AUDIT_LIST_RULES requests.
 | 
					 * AUDIT_LIST_RULES requests.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								init/Kconfig
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								init/Kconfig
									
										
									
									
									
								
							| 
						 | 
					@ -301,20 +301,6 @@ config AUDIT_TREE
 | 
				
			||||||
	depends on AUDITSYSCALL
 | 
						depends on AUDITSYSCALL
 | 
				
			||||||
	select FSNOTIFY
 | 
						select FSNOTIFY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config AUDIT_LOGINUID_IMMUTABLE
 | 
					 | 
				
			||||||
	bool "Make audit loginuid immutable"
 | 
					 | 
				
			||||||
	depends on AUDIT
 | 
					 | 
				
			||||||
	help
 | 
					 | 
				
			||||||
	  The config option toggles if a task setting its loginuid requires
 | 
					 | 
				
			||||||
	  CAP_SYS_AUDITCONTROL or if that task should require no special permissions
 | 
					 | 
				
			||||||
	  but should instead only allow setting its loginuid if it was never
 | 
					 | 
				
			||||||
	  previously set.  On systems which use systemd or a similar central
 | 
					 | 
				
			||||||
	  process to restart login services this should be set to true.  On older
 | 
					 | 
				
			||||||
	  systems in which an admin would typically have to directly stop and
 | 
					 | 
				
			||||||
	  start processes this should be set to false.  Setting this to true allows
 | 
					 | 
				
			||||||
	  one to drop potentially dangerous capabilites from the login tasks,
 | 
					 | 
				
			||||||
	  but may not be backwards compatible with older init systems.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
source "kernel/irq/Kconfig"
 | 
					source "kernel/irq/Kconfig"
 | 
				
			||||||
source "kernel/time/Kconfig"
 | 
					source "kernel/time/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										153
									
								
								kernel/audit.c
									
										
									
									
									
								
							
							
						
						
									
										153
									
								
								kernel/audit.c
									
										
									
									
									
								
							| 
						 | 
					@ -60,7 +60,6 @@
 | 
				
			||||||
#ifdef CONFIG_SECURITY
 | 
					#ifdef CONFIG_SECURITY
 | 
				
			||||||
#include <linux/security.h>
 | 
					#include <linux/security.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include <net/netlink.h>
 | 
					 | 
				
			||||||
#include <linux/freezer.h>
 | 
					#include <linux/freezer.h>
 | 
				
			||||||
#include <linux/tty.h>
 | 
					#include <linux/tty.h>
 | 
				
			||||||
#include <linux/pid_namespace.h>
 | 
					#include <linux/pid_namespace.h>
 | 
				
			||||||
| 
						 | 
					@ -140,6 +139,17 @@ static struct task_struct *kauditd_task;
 | 
				
			||||||
static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
 | 
					static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
 | 
				
			||||||
static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
 | 
					static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct audit_features af = {.vers = AUDIT_FEATURE_VERSION,
 | 
				
			||||||
 | 
									   .mask = -1,
 | 
				
			||||||
 | 
									   .features = 0,
 | 
				
			||||||
 | 
									   .lock = 0,};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *audit_feature_names[2] = {
 | 
				
			||||||
 | 
						"only_unset_loginuid",
 | 
				
			||||||
 | 
						"loginuid_immutable",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Serialize requests from userspace. */
 | 
					/* Serialize requests from userspace. */
 | 
				
			||||||
DEFINE_MUTEX(audit_cmd_mutex);
 | 
					DEFINE_MUTEX(audit_cmd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -584,6 +594,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
	case AUDIT_GET:
 | 
						case AUDIT_GET:
 | 
				
			||||||
	case AUDIT_SET:
 | 
						case AUDIT_SET:
 | 
				
			||||||
 | 
						case AUDIT_GET_FEATURE:
 | 
				
			||||||
 | 
						case AUDIT_SET_FEATURE:
 | 
				
			||||||
	case AUDIT_LIST_RULES:
 | 
						case AUDIT_LIST_RULES:
 | 
				
			||||||
	case AUDIT_ADD_RULE:
 | 
						case AUDIT_ADD_RULE:
 | 
				
			||||||
	case AUDIT_DEL_RULE:
 | 
						case AUDIT_DEL_RULE:
 | 
				
			||||||
| 
						 | 
					@ -613,7 +625,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	uid_t uid = from_kuid(&init_user_ns, current_uid());
 | 
						uid_t uid = from_kuid(&init_user_ns, current_uid());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!audit_enabled) {
 | 
						if (!audit_enabled && msg_type != AUDIT_USER_AVC) {
 | 
				
			||||||
		*ab = NULL;
 | 
							*ab = NULL;
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -628,6 +640,94 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int is_audit_feature_set(int i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return af.features & AUDIT_FEATURE_TO_MASK(i);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int audit_get_feature(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seq = nlmsg_hdr(skb)->nlmsg_seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
 | 
				
			||||||
 | 
								 &af, sizeof(af));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature,
 | 
				
			||||||
 | 
									     u32 old_lock, u32 new_lock, int res)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct audit_buffer *ab;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
 | 
				
			||||||
 | 
						audit_log_format(ab, "feature=%s new=%d old=%d old_lock=%d new_lock=%d res=%d",
 | 
				
			||||||
 | 
								 audit_feature_names[which], !!old_feature, !!new_feature,
 | 
				
			||||||
 | 
								 !!old_lock, !!new_lock, res);
 | 
				
			||||||
 | 
						audit_log_end(ab);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int audit_set_feature(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct audit_features *uaf;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > sizeof(audit_feature_names)/sizeof(audit_feature_names[0]));
 | 
				
			||||||
 | 
						uaf = nlmsg_data(nlmsg_hdr(skb));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* if there is ever a version 2 we should handle that here */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
 | 
				
			||||||
 | 
							u32 feature = AUDIT_FEATURE_TO_MASK(i);
 | 
				
			||||||
 | 
							u32 old_feature, new_feature, old_lock, new_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* if we are not changing this feature, move along */
 | 
				
			||||||
 | 
							if (!(feature & uaf->mask))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							old_feature = af.features & feature;
 | 
				
			||||||
 | 
							new_feature = uaf->features & feature;
 | 
				
			||||||
 | 
							new_lock = (uaf->lock | af.lock) & feature;
 | 
				
			||||||
 | 
							old_lock = af.lock & feature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* are we changing a locked feature? */
 | 
				
			||||||
 | 
							if ((af.lock & feature) && (new_feature != old_feature)) {
 | 
				
			||||||
 | 
								audit_log_feature_change(i, old_feature, new_feature,
 | 
				
			||||||
 | 
											 old_lock, new_lock, 0);
 | 
				
			||||||
 | 
								return -EPERM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* nothing invalid, do the changes */
 | 
				
			||||||
 | 
						for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
 | 
				
			||||||
 | 
							u32 feature = AUDIT_FEATURE_TO_MASK(i);
 | 
				
			||||||
 | 
							u32 old_feature, new_feature, old_lock, new_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* if we are not changing this feature, move along */
 | 
				
			||||||
 | 
							if (!(feature & uaf->mask))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							old_feature = af.features & feature;
 | 
				
			||||||
 | 
							new_feature = uaf->features & feature;
 | 
				
			||||||
 | 
							old_lock = af.lock & feature;
 | 
				
			||||||
 | 
							new_lock = (uaf->lock | af.lock) & feature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (new_feature != old_feature)
 | 
				
			||||||
 | 
								audit_log_feature_change(i, old_feature, new_feature,
 | 
				
			||||||
 | 
											 old_lock, new_lock, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (new_feature)
 | 
				
			||||||
 | 
								af.features |= feature;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								af.features &= ~feature;
 | 
				
			||||||
 | 
							af.lock |= new_lock;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
					static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32			seq;
 | 
						u32			seq;
 | 
				
			||||||
| 
						 | 
					@ -659,6 +759,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (msg_type) {
 | 
						switch (msg_type) {
 | 
				
			||||||
	case AUDIT_GET:
 | 
						case AUDIT_GET:
 | 
				
			||||||
 | 
							memset(&status_set, 0, sizeof(status_set));
 | 
				
			||||||
		status_set.enabled	 = audit_enabled;
 | 
							status_set.enabled	 = audit_enabled;
 | 
				
			||||||
		status_set.failure	 = audit_failure;
 | 
							status_set.failure	 = audit_failure;
 | 
				
			||||||
		status_set.pid		 = audit_pid;
 | 
							status_set.pid		 = audit_pid;
 | 
				
			||||||
| 
						 | 
					@ -670,7 +771,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
				
			||||||
				 &status_set, sizeof(status_set));
 | 
									 &status_set, sizeof(status_set));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case AUDIT_SET:
 | 
						case AUDIT_SET:
 | 
				
			||||||
		if (nlh->nlmsg_len < sizeof(struct audit_status))
 | 
							if (nlmsg_len(nlh) < sizeof(struct audit_status))
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		status_get   = (struct audit_status *)data;
 | 
							status_get   = (struct audit_status *)data;
 | 
				
			||||||
		if (status_get->mask & AUDIT_STATUS_ENABLED) {
 | 
							if (status_get->mask & AUDIT_STATUS_ENABLED) {
 | 
				
			||||||
| 
						 | 
					@ -699,6 +800,16 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
				
			||||||
		if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
 | 
							if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
 | 
				
			||||||
			err = audit_set_backlog_limit(status_get->backlog_limit);
 | 
								err = audit_set_backlog_limit(status_get->backlog_limit);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case AUDIT_GET_FEATURE:
 | 
				
			||||||
 | 
							err = audit_get_feature(skb);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case AUDIT_SET_FEATURE:
 | 
				
			||||||
 | 
							err = audit_set_feature(skb);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	case AUDIT_USER:
 | 
						case AUDIT_USER:
 | 
				
			||||||
	case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
 | 
						case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
 | 
				
			||||||
	case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
 | 
						case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
 | 
				
			||||||
| 
						 | 
					@ -715,7 +826,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			audit_log_common_recv_msg(&ab, msg_type);
 | 
								audit_log_common_recv_msg(&ab, msg_type);
 | 
				
			||||||
			if (msg_type != AUDIT_USER_TTY)
 | 
								if (msg_type != AUDIT_USER_TTY)
 | 
				
			||||||
				audit_log_format(ab, " msg='%.1024s'",
 | 
									audit_log_format(ab, " msg='%.*s'",
 | 
				
			||||||
 | 
											 AUDIT_MESSAGE_TEXT_MAX,
 | 
				
			||||||
						 (char *)data);
 | 
											 (char *)data);
 | 
				
			||||||
			else {
 | 
								else {
 | 
				
			||||||
				int size;
 | 
									int size;
 | 
				
			||||||
| 
						 | 
					@ -818,7 +930,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
				
			||||||
		struct task_struct *tsk = current;
 | 
							struct task_struct *tsk = current;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spin_lock(&tsk->sighand->siglock);
 | 
							spin_lock(&tsk->sighand->siglock);
 | 
				
			||||||
		s.enabled = tsk->signal->audit_tty != 0;
 | 
							s.enabled = tsk->signal->audit_tty;
 | 
				
			||||||
		s.log_passwd = tsk->signal->audit_tty_log_passwd;
 | 
							s.log_passwd = tsk->signal->audit_tty_log_passwd;
 | 
				
			||||||
		spin_unlock(&tsk->sighand->siglock);
 | 
							spin_unlock(&tsk->sighand->siglock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -832,7 +944,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		memset(&s, 0, sizeof(s));
 | 
							memset(&s, 0, sizeof(s));
 | 
				
			||||||
		/* guard against past and future API changes */
 | 
							/* guard against past and future API changes */
 | 
				
			||||||
		memcpy(&s, data, min(sizeof(s), (size_t)nlh->nlmsg_len));
 | 
							memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
 | 
				
			||||||
		if ((s.enabled != 0 && s.enabled != 1) ||
 | 
							if ((s.enabled != 0 && s.enabled != 1) ||
 | 
				
			||||||
		    (s.log_passwd != 0 && s.log_passwd != 1))
 | 
							    (s.log_passwd != 0 && s.log_passwd != 1))
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -1067,13 +1179,6 @@ static void wait_for_auditd(unsigned long sleep_time)
 | 
				
			||||||
	remove_wait_queue(&audit_backlog_wait, &wait);
 | 
						remove_wait_queue(&audit_backlog_wait, &wait);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Obtain an audit buffer.  This routine does locking to obtain the
 | 
					 | 
				
			||||||
 * audit buffer, but then no locking is required for calls to
 | 
					 | 
				
			||||||
 * audit_log_*format.  If the tsk is a task that is currently in a
 | 
					 | 
				
			||||||
 * syscall, then the syscall is marked as auditable and an audit record
 | 
					 | 
				
			||||||
 * will be written at syscall exit.  If there is no associated task, tsk
 | 
					 | 
				
			||||||
 * should be NULL. */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * audit_log_start - obtain an audit buffer
 | 
					 * audit_log_start - obtain an audit buffer
 | 
				
			||||||
 * @ctx: audit_context (may be NULL)
 | 
					 * @ctx: audit_context (may be NULL)
 | 
				
			||||||
| 
						 | 
					@ -1389,7 +1494,7 @@ void audit_log_session_info(struct audit_buffer *ab)
 | 
				
			||||||
	u32 sessionid = audit_get_sessionid(current);
 | 
						u32 sessionid = audit_get_sessionid(current);
 | 
				
			||||||
	uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
 | 
						uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audit_log_format(ab, " auid=%u ses=%u\n", auid, sessionid);
 | 
						audit_log_format(ab, " auid=%u ses=%u", auid, sessionid);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void audit_log_key(struct audit_buffer *ab, char *key)
 | 
					void audit_log_key(struct audit_buffer *ab, char *key)
 | 
				
			||||||
| 
						 | 
					@ -1536,6 +1641,26 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* log the audit_names record type */
 | 
				
			||||||
 | 
						audit_log_format(ab, " nametype=");
 | 
				
			||||||
 | 
						switch(n->type) {
 | 
				
			||||||
 | 
						case AUDIT_TYPE_NORMAL:
 | 
				
			||||||
 | 
							audit_log_format(ab, "NORMAL");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case AUDIT_TYPE_PARENT:
 | 
				
			||||||
 | 
							audit_log_format(ab, "PARENT");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case AUDIT_TYPE_CHILD_DELETE:
 | 
				
			||||||
 | 
							audit_log_format(ab, "DELETE");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case AUDIT_TYPE_CHILD_CREATE:
 | 
				
			||||||
 | 
							audit_log_format(ab, "CREATE");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							audit_log_format(ab, "UNKNOWN");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audit_log_fcaps(ab, n);
 | 
						audit_log_fcaps(ab, n);
 | 
				
			||||||
	audit_log_end(ab);
 | 
						audit_log_end(ab);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -197,6 +197,9 @@ struct audit_context {
 | 
				
			||||||
			int			fd;
 | 
								int			fd;
 | 
				
			||||||
			int			flags;
 | 
								int			flags;
 | 
				
			||||||
		} mmap;
 | 
							} mmap;
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								int			argc;
 | 
				
			||||||
 | 
							} execve;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	int fds[2];
 | 
						int fds[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -343,6 +343,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
 | 
				
			||||||
	case AUDIT_DEVMINOR:
 | 
						case AUDIT_DEVMINOR:
 | 
				
			||||||
	case AUDIT_EXIT:
 | 
						case AUDIT_EXIT:
 | 
				
			||||||
	case AUDIT_SUCCESS:
 | 
						case AUDIT_SUCCESS:
 | 
				
			||||||
 | 
						case AUDIT_INODE:
 | 
				
			||||||
		/* bit ops are only useful on syscall args */
 | 
							/* bit ops are only useful on syscall args */
 | 
				
			||||||
		if (f->op == Audit_bitmask || f->op == Audit_bittest)
 | 
							if (f->op == Audit_bitmask || f->op == Audit_bittest)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -423,7 +424,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 | 
				
			||||||
		f->lsm_rule = NULL;
 | 
							f->lsm_rule = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Support legacy tests for a valid loginuid */
 | 
							/* Support legacy tests for a valid loginuid */
 | 
				
			||||||
		if ((f->type == AUDIT_LOGINUID) && (f->val == ~0U)) {
 | 
							if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
 | 
				
			||||||
			f->type = AUDIT_LOGINUID_SET;
 | 
								f->type = AUDIT_LOGINUID_SET;
 | 
				
			||||||
			f->val = 0;
 | 
								f->val = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										133
									
								
								kernel/auditsc.c
									
										
									
									
									
								
							
							
						
						
									
										133
									
								
								kernel/auditsc.c
									
										
									
									
									
								
							| 
						 | 
					@ -95,13 +95,6 @@ struct audit_aux_data {
 | 
				
			||||||
/* Number of target pids per aux struct. */
 | 
					/* Number of target pids per aux struct. */
 | 
				
			||||||
#define AUDIT_AUX_PIDS	16
 | 
					#define AUDIT_AUX_PIDS	16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct audit_aux_data_execve {
 | 
					 | 
				
			||||||
	struct audit_aux_data	d;
 | 
					 | 
				
			||||||
	int argc;
 | 
					 | 
				
			||||||
	int envc;
 | 
					 | 
				
			||||||
	struct mm_struct *mm;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct audit_aux_data_pids {
 | 
					struct audit_aux_data_pids {
 | 
				
			||||||
	struct audit_aux_data	d;
 | 
						struct audit_aux_data	d;
 | 
				
			||||||
	pid_t			target_pid[AUDIT_AUX_PIDS];
 | 
						pid_t			target_pid[AUDIT_AUX_PIDS];
 | 
				
			||||||
| 
						 | 
					@ -121,12 +114,6 @@ struct audit_aux_data_bprm_fcaps {
 | 
				
			||||||
	struct audit_cap_data	new_pcap;
 | 
						struct audit_cap_data	new_pcap;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct audit_aux_data_capset {
 | 
					 | 
				
			||||||
	struct audit_aux_data	d;
 | 
					 | 
				
			||||||
	pid_t			pid;
 | 
					 | 
				
			||||||
	struct audit_cap_data	cap;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct audit_tree_refs {
 | 
					struct audit_tree_refs {
 | 
				
			||||||
	struct audit_tree_refs *next;
 | 
						struct audit_tree_refs *next;
 | 
				
			||||||
	struct audit_chunk *c[31];
 | 
						struct audit_chunk *c[31];
 | 
				
			||||||
| 
						 | 
					@ -566,7 +553,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case AUDIT_INODE:
 | 
							case AUDIT_INODE:
 | 
				
			||||||
			if (name)
 | 
								if (name)
 | 
				
			||||||
				result = (name->ino == f->val);
 | 
									result = audit_comparator(name->ino, f->op, f->val);
 | 
				
			||||||
			else if (ctx) {
 | 
								else if (ctx) {
 | 
				
			||||||
				list_for_each_entry(n, &ctx->names_list, list) {
 | 
									list_for_each_entry(n, &ctx->names_list, list) {
 | 
				
			||||||
					if (audit_comparator(n->ino, f->op, f->val)) {
 | 
										if (audit_comparator(n->ino, f->op, f->val)) {
 | 
				
			||||||
| 
						 | 
					@ -943,8 +930,10 @@ int audit_alloc(struct task_struct *tsk)
 | 
				
			||||||
		return 0; /* Return if not auditing. */
 | 
							return 0; /* Return if not auditing. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state = audit_filter_task(tsk, &key);
 | 
						state = audit_filter_task(tsk, &key);
 | 
				
			||||||
	if (state == AUDIT_DISABLED)
 | 
						if (state == AUDIT_DISABLED) {
 | 
				
			||||||
 | 
							clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(context = audit_alloc_context(state))) {
 | 
						if (!(context = audit_alloc_context(state))) {
 | 
				
			||||||
		kfree(key);
 | 
							kfree(key);
 | 
				
			||||||
| 
						 | 
					@ -1149,20 +1138,16 @@ static int audit_log_single_execve_arg(struct audit_context *context,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void audit_log_execve_info(struct audit_context *context,
 | 
					static void audit_log_execve_info(struct audit_context *context,
 | 
				
			||||||
				  struct audit_buffer **ab,
 | 
									  struct audit_buffer **ab)
 | 
				
			||||||
				  struct audit_aux_data_execve *axi)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, len;
 | 
						int i, len;
 | 
				
			||||||
	size_t len_sent = 0;
 | 
						size_t len_sent = 0;
 | 
				
			||||||
	const char __user *p;
 | 
						const char __user *p;
 | 
				
			||||||
	char *buf;
 | 
						char *buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (axi->mm != current->mm)
 | 
						p = (const char __user *)current->mm->arg_start;
 | 
				
			||||||
		return; /* execve failed, no additional info */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = (const char __user *)axi->mm->arg_start;
 | 
						audit_log_format(*ab, "argc=%d", context->execve.argc);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	audit_log_format(*ab, "argc=%d", axi->argc);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * we need some kernel buffer to hold the userspace args.  Just
 | 
						 * we need some kernel buffer to hold the userspace args.  Just
 | 
				
			||||||
| 
						 | 
					@ -1176,7 +1161,7 @@ static void audit_log_execve_info(struct audit_context *context,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < axi->argc; i++) {
 | 
						for (i = 0; i < context->execve.argc; i++) {
 | 
				
			||||||
		len = audit_log_single_execve_arg(context, ab, i,
 | 
							len = audit_log_single_execve_arg(context, ab, i,
 | 
				
			||||||
						  &len_sent, p, buf);
 | 
											  &len_sent, p, buf);
 | 
				
			||||||
		if (len <= 0)
 | 
							if (len <= 0)
 | 
				
			||||||
| 
						 | 
					@ -1279,6 +1264,9 @@ static void show_special(struct audit_context *context, int *call_panic)
 | 
				
			||||||
		audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
 | 
							audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
 | 
				
			||||||
				 context->mmap.flags);
 | 
									 context->mmap.flags);
 | 
				
			||||||
		break; }
 | 
							break; }
 | 
				
			||||||
 | 
						case AUDIT_EXECVE: {
 | 
				
			||||||
 | 
							audit_log_execve_info(context, &ab);
 | 
				
			||||||
 | 
							break; }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	audit_log_end(ab);
 | 
						audit_log_end(ab);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1325,11 +1313,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (aux->type) {
 | 
							switch (aux->type) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case AUDIT_EXECVE: {
 | 
					 | 
				
			||||||
			struct audit_aux_data_execve *axi = (void *)aux;
 | 
					 | 
				
			||||||
			audit_log_execve_info(context, &ab, axi);
 | 
					 | 
				
			||||||
			break; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case AUDIT_BPRM_FCAPS: {
 | 
							case AUDIT_BPRM_FCAPS: {
 | 
				
			||||||
			struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
 | 
								struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
 | 
				
			||||||
			audit_log_format(ab, "fver=%x", axs->fcap_ver);
 | 
								audit_log_format(ab, "fver=%x", axs->fcap_ver);
 | 
				
			||||||
| 
						 | 
					@ -1964,6 +1947,43 @@ int auditsc_get_stamp(struct audit_context *ctx,
 | 
				
			||||||
/* global counter which is incremented every time something logs in */
 | 
					/* global counter which is incremented every time something logs in */
 | 
				
			||||||
static atomic_t session_id = ATOMIC_INIT(0);
 | 
					static atomic_t session_id = ATOMIC_INIT(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int audit_set_loginuid_perm(kuid_t loginuid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* if we are unset, we don't need privs */
 | 
				
			||||||
 | 
						if (!audit_loginuid_set(current))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						/* if AUDIT_FEATURE_LOGINUID_IMMUTABLE means never ever allow a change*/
 | 
				
			||||||
 | 
						if (is_audit_feature_set(AUDIT_FEATURE_LOGINUID_IMMUTABLE))
 | 
				
			||||||
 | 
							return -EPERM;
 | 
				
			||||||
 | 
						/* it is set, you need permission */
 | 
				
			||||||
 | 
						if (!capable(CAP_AUDIT_CONTROL))
 | 
				
			||||||
 | 
							return -EPERM;
 | 
				
			||||||
 | 
						/* reject if this is not an unset and we don't allow that */
 | 
				
			||||||
 | 
						if (is_audit_feature_set(AUDIT_FEATURE_ONLY_UNSET_LOGINUID) && uid_valid(loginuid))
 | 
				
			||||||
 | 
							return -EPERM;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
 | 
				
			||||||
 | 
									   unsigned int oldsessionid, unsigned int sessionid,
 | 
				
			||||||
 | 
									   int rc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct audit_buffer *ab;
 | 
				
			||||||
 | 
						uid_t uid, ologinuid, nloginuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uid = from_kuid(&init_user_ns, task_uid(current));
 | 
				
			||||||
 | 
						ologinuid = from_kuid(&init_user_ns, koldloginuid);
 | 
				
			||||||
 | 
						nloginuid = from_kuid(&init_user_ns, kloginuid),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
 | 
				
			||||||
 | 
						if (!ab)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						audit_log_format(ab, "pid=%d uid=%u old auid=%u new auid=%u old "
 | 
				
			||||||
 | 
								 "ses=%u new ses=%u res=%d", current->pid, uid, ologinuid,
 | 
				
			||||||
 | 
								 nloginuid, oldsessionid, sessionid, !rc);
 | 
				
			||||||
 | 
						audit_log_end(ab);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * audit_set_loginuid - set current task's audit_context loginuid
 | 
					 * audit_set_loginuid - set current task's audit_context loginuid
 | 
				
			||||||
 * @loginuid: loginuid value
 | 
					 * @loginuid: loginuid value
 | 
				
			||||||
| 
						 | 
					@ -1975,37 +1995,26 @@ static atomic_t session_id = ATOMIC_INIT(0);
 | 
				
			||||||
int audit_set_loginuid(kuid_t loginuid)
 | 
					int audit_set_loginuid(kuid_t loginuid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *task = current;
 | 
						struct task_struct *task = current;
 | 
				
			||||||
	struct audit_context *context = task->audit_context;
 | 
						unsigned int oldsessionid, sessionid = (unsigned int)-1;
 | 
				
			||||||
	unsigned int sessionid;
 | 
						kuid_t oldloginuid;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
 | 
						oldloginuid = audit_get_loginuid(current);
 | 
				
			||||||
	if (audit_loginuid_set(task))
 | 
						oldsessionid = audit_get_sessionid(current);
 | 
				
			||||||
		return -EPERM;
 | 
					 | 
				
			||||||
#else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
 | 
					 | 
				
			||||||
	if (!capable(CAP_AUDIT_CONTROL))
 | 
					 | 
				
			||||||
		return -EPERM;
 | 
					 | 
				
			||||||
#endif  /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sessionid = atomic_inc_return(&session_id);
 | 
						rc = audit_set_loginuid_perm(loginuid);
 | 
				
			||||||
	if (context && context->in_syscall) {
 | 
						if (rc)
 | 
				
			||||||
		struct audit_buffer *ab;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* are we setting or clearing? */
 | 
				
			||||||
 | 
						if (uid_valid(loginuid))
 | 
				
			||||||
 | 
							sessionid = atomic_inc_return(&session_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
 | 
					 | 
				
			||||||
		if (ab) {
 | 
					 | 
				
			||||||
			audit_log_format(ab, "login pid=%d uid=%u "
 | 
					 | 
				
			||||||
				"old auid=%u new auid=%u"
 | 
					 | 
				
			||||||
				" old ses=%u new ses=%u",
 | 
					 | 
				
			||||||
				task->pid,
 | 
					 | 
				
			||||||
				from_kuid(&init_user_ns, task_uid(task)),
 | 
					 | 
				
			||||||
				from_kuid(&init_user_ns, task->loginuid),
 | 
					 | 
				
			||||||
				from_kuid(&init_user_ns, loginuid),
 | 
					 | 
				
			||||||
				task->sessionid, sessionid);
 | 
					 | 
				
			||||||
			audit_log_end(ab);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	task->sessionid = sessionid;
 | 
						task->sessionid = sessionid;
 | 
				
			||||||
	task->loginuid = loginuid;
 | 
						task->loginuid = loginuid;
 | 
				
			||||||
	return 0;
 | 
					out:
 | 
				
			||||||
 | 
						audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -2126,22 +2135,12 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mo
 | 
				
			||||||
	context->ipc.has_perm = 1;
 | 
						context->ipc.has_perm = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __audit_bprm(struct linux_binprm *bprm)
 | 
					void __audit_bprm(struct linux_binprm *bprm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct audit_aux_data_execve *ax;
 | 
					 | 
				
			||||||
	struct audit_context *context = current->audit_context;
 | 
						struct audit_context *context = current->audit_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
 | 
						context->type = AUDIT_EXECVE;
 | 
				
			||||||
	if (!ax)
 | 
						context->execve.argc = bprm->argc;
 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ax->argc = bprm->argc;
 | 
					 | 
				
			||||||
	ax->envc = bprm->envc;
 | 
					 | 
				
			||||||
	ax->mm = bprm->mm;
 | 
					 | 
				
			||||||
	ax->d.type = AUDIT_EXECVE;
 | 
					 | 
				
			||||||
	ax->d.next = context->aux;
 | 
					 | 
				
			||||||
	context->aux = (void *)ax;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,7 +397,8 @@ void common_lsm_audit(struct common_audit_data *a,
 | 
				
			||||||
	if (a == NULL)
 | 
						if (a == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	/* we use GFP_ATOMIC so we won't sleep */
 | 
						/* we use GFP_ATOMIC so we won't sleep */
 | 
				
			||||||
	ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
 | 
						ab = audit_log_start(current->audit_context, GFP_ATOMIC | __GFP_NOWARN,
 | 
				
			||||||
 | 
								     AUDIT_AVC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ab == NULL)
 | 
						if (ab == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,6 +116,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
 | 
				
			||||||
	{ AUDIT_MAKE_EQUIV,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
 | 
						{ AUDIT_MAKE_EQUIV,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
 | 
				
			||||||
	{ AUDIT_TTY_GET,	NETLINK_AUDIT_SOCKET__NLMSG_READ     },
 | 
						{ AUDIT_TTY_GET,	NETLINK_AUDIT_SOCKET__NLMSG_READ     },
 | 
				
			||||||
	{ AUDIT_TTY_SET,	NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT	},
 | 
						{ AUDIT_TTY_SET,	NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT	},
 | 
				
			||||||
 | 
						{ AUDIT_GET_FEATURE,	NETLINK_AUDIT_SOCKET__NLMSG_READ     },
 | 
				
			||||||
 | 
						{ AUDIT_SET_FEATURE,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue