audit: ignore fcaps on umount
Don't fetch fcaps when umount2 is called to avoid a process hang while it waits for the missing resource to (possibly never) re-appear. Note the comment above user_path_mountpoint_at(): * A umount is a special case for path walking. We're not actually interested * in the inode in this situation, and ESTALE errors can be a problem. We * simply want track down the dentry and vfsmount attached at the mountpoint * and avoid revalidating the last component. This can happen on ceph, cifs, 9p, lustre, fuse (gluster) or NFS. Please see the github issue tracker https://github.com/linux-audit/audit-kernel/issues/100 Signed-off-by: Richard Guy Briggs <rgb@redhat.com> [PM: merge fuzz in audit_log_fcaps()] Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
		
							parent
							
								
									05c7a9cb27
								
							
						
					
					
						commit
						57d4657716
					
				| @ -2720,7 +2720,7 @@ filename_mountpoint(int dfd, struct filename *name, struct path *path, | ||||
| 	if (unlikely(error == -ESTALE)) | ||||
| 		error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path); | ||||
| 	if (likely(!error)) | ||||
| 		audit_inode(name, path->dentry, 0); | ||||
| 		audit_inode(name, path->dentry, flags & LOOKUP_NO_EVAL); | ||||
| 	restore_nameidata(); | ||||
| 	putname(name); | ||||
| 	return error; | ||||
|  | ||||
| @ -1640,6 +1640,8 @@ int ksys_umount(char __user *name, int flags) | ||||
| 	if (!(flags & UMOUNT_NOFOLLOW)) | ||||
| 		lookup_flags |= LOOKUP_FOLLOW; | ||||
| 
 | ||||
| 	lookup_flags |= LOOKUP_NO_EVAL; | ||||
| 
 | ||||
| 	retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path); | ||||
| 	if (retval) | ||||
| 		goto out; | ||||
|  | ||||
| @ -25,6 +25,7 @@ | ||||
| 
 | ||||
| #include <linux/sched.h> | ||||
| #include <linux/ptrace.h> | ||||
| #include <linux/namei.h>  /* LOOKUP_* */ | ||||
| #include <uapi/linux/audit.h> | ||||
| 
 | ||||
| #define AUDIT_INO_UNSET ((unsigned long)-1) | ||||
| @ -248,6 +249,7 @@ extern void __audit_getname(struct filename *name); | ||||
| 
 | ||||
| #define AUDIT_INODE_PARENT	1	/* dentry represents the parent */ | ||||
| #define AUDIT_INODE_HIDDEN	2	/* audit record should be hidden */ | ||||
| #define AUDIT_INODE_NOEVAL	4	/* audit record incomplete */ | ||||
| extern void __audit_inode(struct filename *name, const struct dentry *dentry, | ||||
| 				unsigned int flags); | ||||
| extern void __audit_file(const struct file *); | ||||
| @ -308,12 +310,15 @@ static inline void audit_getname(struct filename *name) | ||||
| } | ||||
| static inline void audit_inode(struct filename *name, | ||||
| 				const struct dentry *dentry, | ||||
| 				unsigned int parent) { | ||||
| 				unsigned int flags) { | ||||
| 	if (unlikely(!audit_dummy_context())) { | ||||
| 		unsigned int flags = 0; | ||||
| 		if (parent) | ||||
| 			flags |= AUDIT_INODE_PARENT; | ||||
| 		__audit_inode(name, dentry, flags); | ||||
| 		unsigned int aflags = 0; | ||||
| 
 | ||||
| 		if (flags & LOOKUP_PARENT) | ||||
| 			aflags |= AUDIT_INODE_PARENT; | ||||
| 		if (flags & LOOKUP_NO_EVAL) | ||||
| 			aflags |= AUDIT_INODE_NOEVAL; | ||||
| 		__audit_inode(name, dentry, aflags); | ||||
| 	} | ||||
| } | ||||
| static inline void audit_file(struct file *file) | ||||
|  | ||||
| @ -24,6 +24,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; | ||||
|  *  - internal "there are more path components" flag | ||||
|  *  - dentry cache is untrusted; force a real lookup | ||||
|  *  - suppress terminal automount | ||||
|  *  - skip revalidation | ||||
|  *  - don't fetch xattrs on audit_inode | ||||
|  */ | ||||
| #define LOOKUP_FOLLOW		0x0001 | ||||
| #define LOOKUP_DIRECTORY	0x0002 | ||||
| @ -33,6 +35,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; | ||||
| #define LOOKUP_REVAL		0x0020 | ||||
| #define LOOKUP_RCU		0x0040 | ||||
| #define LOOKUP_NO_REVAL		0x0080 | ||||
| #define LOOKUP_NO_EVAL		0x0100 | ||||
| 
 | ||||
| /*
 | ||||
|  * Intent data | ||||
|  | ||||
| @ -2082,6 +2082,10 @@ void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) | ||||
| 
 | ||||
| static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) | ||||
| { | ||||
| 	if (name->fcap_ver == -1) { | ||||
| 		audit_log_format(ab, " cap_fe=? cap_fver=? cap_fp=? cap_fi=?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	audit_log_cap(ab, "cap_fp", &name->fcap.permitted); | ||||
| 	audit_log_cap(ab, "cap_fi", &name->fcap.inheritable); | ||||
| 	audit_log_format(ab, " cap_fe=%d cap_fver=%x cap_frootid=%d", | ||||
| @ -2114,7 +2118,7 @@ static inline int audit_copy_fcaps(struct audit_names *name, | ||||
| 
 | ||||
| /* Copy inode data into an audit_names. */ | ||||
| void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, | ||||
| 		      struct inode *inode) | ||||
| 		      struct inode *inode, unsigned int flags) | ||||
| { | ||||
| 	name->ino   = inode->i_ino; | ||||
| 	name->dev   = inode->i_sb->s_dev; | ||||
| @ -2123,6 +2127,10 @@ void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, | ||||
| 	name->gid   = inode->i_gid; | ||||
| 	name->rdev  = inode->i_rdev; | ||||
| 	security_inode_getsecid(inode, &name->osid); | ||||
| 	if (flags & AUDIT_INODE_NOEVAL) { | ||||
| 		name->fcap_ver = -1; | ||||
| 		return; | ||||
| 	} | ||||
| 	audit_copy_fcaps(name, dentry); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -215,7 +215,7 @@ extern void audit_log_session_info(struct audit_buffer *ab); | ||||
| 
 | ||||
| extern void audit_copy_inode(struct audit_names *name, | ||||
| 			     const struct dentry *dentry, | ||||
| 			     struct inode *inode); | ||||
| 			     struct inode *inode, unsigned int flags); | ||||
| extern void audit_log_cap(struct audit_buffer *ab, char *prefix, | ||||
| 			  kernel_cap_t *cap); | ||||
| extern void audit_log_name(struct audit_context *context, | ||||
|  | ||||
| @ -1856,7 +1856,7 @@ out: | ||||
| 		n->type = AUDIT_TYPE_NORMAL; | ||||
| 	} | ||||
| 	handle_path(dentry); | ||||
| 	audit_copy_inode(n, dentry, inode); | ||||
| 	audit_copy_inode(n, dentry, inode, flags & AUDIT_INODE_NOEVAL); | ||||
| } | ||||
| 
 | ||||
| void __audit_file(const struct file *file) | ||||
| @ -1955,7 +1955,7 @@ void __audit_inode_child(struct inode *parent, | ||||
| 		n = audit_alloc_name(context, AUDIT_TYPE_PARENT); | ||||
| 		if (!n) | ||||
| 			return; | ||||
| 		audit_copy_inode(n, NULL, parent); | ||||
| 		audit_copy_inode(n, NULL, parent, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!found_child) { | ||||
| @ -1974,7 +1974,7 @@ void __audit_inode_child(struct inode *parent, | ||||
| 	} | ||||
| 
 | ||||
| 	if (inode) | ||||
| 		audit_copy_inode(found_child, dentry, inode); | ||||
| 		audit_copy_inode(found_child, dentry, inode, 0); | ||||
| 	else | ||||
| 		found_child->ino = AUDIT_INO_UNSET; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user