forked from mirrors/linux
		
	selinux: slow_avc_audit has become non-blocking
dump_common_audit_data() is safe to use under rcu_read_lock() now; no need for AVC_NONBLOCKING and games around it Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
		
							parent
							
								
									d0a83314db
								
							
						
					
					
						commit
						b17ec22fb3
					
				
					 3 changed files with 10 additions and 35 deletions
				
			
		| 
						 | 
					@ -759,7 +759,11 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is the slow part of avc audit with big stack footprint */
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the slow part of avc audit with big stack footprint.
 | 
				
			||||||
 | 
					 * Note that it is non-blocking and can be called from under
 | 
				
			||||||
 | 
					 * rcu_read_lock().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
noinline int slow_avc_audit(struct selinux_state *state,
 | 
					noinline int slow_avc_audit(struct selinux_state *state,
 | 
				
			||||||
			    u32 ssid, u32 tsid, u16 tclass,
 | 
								    u32 ssid, u32 tsid, u16 tclass,
 | 
				
			||||||
			    u32 requested, u32 audited, u32 denied, int result,
 | 
								    u32 requested, u32 audited, u32 denied, int result,
 | 
				
			||||||
| 
						 | 
					@ -826,7 +830,7 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
 | 
				
			||||||
 * @ssid,@tsid,@tclass : identifier of an AVC entry
 | 
					 * @ssid,@tsid,@tclass : identifier of an AVC entry
 | 
				
			||||||
 * @seqno : sequence number when decision was made
 | 
					 * @seqno : sequence number when decision was made
 | 
				
			||||||
 * @xpd: extended_perms_decision to be added to the node
 | 
					 * @xpd: extended_perms_decision to be added to the node
 | 
				
			||||||
 * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0.
 | 
					 * @flags: the AVC_* flags, e.g. AVC_EXTENDED_PERMS, or 0.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * if a valid AVC entry doesn't exist,this function returns -ENOENT.
 | 
					 * if a valid AVC entry doesn't exist,this function returns -ENOENT.
 | 
				
			||||||
 * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
 | 
					 * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
 | 
				
			||||||
| 
						 | 
					@ -845,21 +849,6 @@ static int avc_update_node(struct selinux_avc *avc,
 | 
				
			||||||
	struct hlist_head *head;
 | 
						struct hlist_head *head;
 | 
				
			||||||
	spinlock_t *lock;
 | 
						spinlock_t *lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * If we are in a non-blocking code path, e.g. VFS RCU walk,
 | 
					 | 
				
			||||||
	 * then we must not add permissions to a cache entry
 | 
					 | 
				
			||||||
	 * because we will not audit the denial.  Otherwise,
 | 
					 | 
				
			||||||
	 * during the subsequent blocking retry (e.g. VFS ref walk), we
 | 
					 | 
				
			||||||
	 * will find the permissions already granted in the cache entry
 | 
					 | 
				
			||||||
	 * and won't audit anything at all, leading to silent denials in
 | 
					 | 
				
			||||||
	 * permissive mode that only appear when in enforcing mode.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * See the corresponding handling of MAY_NOT_BLOCK in avc_audit()
 | 
					 | 
				
			||||||
	 * and selinux_inode_permission().
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (flags & AVC_NONBLOCKING)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	node = avc_alloc_node(avc);
 | 
						node = avc_alloc_node(avc);
 | 
				
			||||||
	if (!node) {
 | 
						if (!node) {
 | 
				
			||||||
		rc = -ENOMEM;
 | 
							rc = -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -1120,7 +1109,7 @@ int avc_has_extended_perms(struct selinux_state *state,
 | 
				
			||||||
 * @tsid: target security identifier
 | 
					 * @tsid: target security identifier
 | 
				
			||||||
 * @tclass: target security class
 | 
					 * @tclass: target security class
 | 
				
			||||||
 * @requested: requested permissions, interpreted based on @tclass
 | 
					 * @requested: requested permissions, interpreted based on @tclass
 | 
				
			||||||
 * @flags:  AVC_STRICT, AVC_NONBLOCKING, or 0
 | 
					 * @flags:  AVC_STRICT or 0
 | 
				
			||||||
 * @avd: access vector decisions
 | 
					 * @avd: access vector decisions
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Check the AVC to determine whether the @requested permissions are granted
 | 
					 * Check the AVC to determine whether the @requested permissions are granted
 | 
				
			||||||
| 
						 | 
					@ -1205,8 +1194,7 @@ int avc_has_perm_flags(struct selinux_state *state,
 | 
				
			||||||
	struct av_decision avd;
 | 
						struct av_decision avd;
 | 
				
			||||||
	int rc, rc2;
 | 
						int rc, rc2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested,
 | 
						rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
 | 
				
			||||||
				  (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
 | 
					 | 
				
			||||||
				  &avd);
 | 
									  &avd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
 | 
						rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3164,17 +3164,13 @@ static noinline int audit_inode_permission(struct inode *inode,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct common_audit_data ad;
 | 
						struct common_audit_data ad;
 | 
				
			||||||
	struct inode_security_struct *isec = selinux_inode(inode);
 | 
						struct inode_security_struct *isec = selinux_inode(inode);
 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ad.type = LSM_AUDIT_DATA_INODE;
 | 
						ad.type = LSM_AUDIT_DATA_INODE;
 | 
				
			||||||
	ad.u.inode = inode;
 | 
						ad.u.inode = inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = slow_avc_audit(&selinux_state,
 | 
						return slow_avc_audit(&selinux_state,
 | 
				
			||||||
			    current_sid(), isec->sid, isec->sclass, perms,
 | 
								    current_sid(), isec->sid, isec->sclass, perms,
 | 
				
			||||||
			    audited, denied, result, &ad);
 | 
								    audited, denied, result, &ad);
 | 
				
			||||||
	if (rc)
 | 
					 | 
				
			||||||
		return rc;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int selinux_inode_permission(struct inode *inode, int mask)
 | 
					static int selinux_inode_permission(struct inode *inode, int mask)
 | 
				
			||||||
| 
						 | 
					@ -3209,8 +3205,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 | 
				
			||||||
		return PTR_ERR(isec);
 | 
							return PTR_ERR(isec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = avc_has_perm_noaudit(&selinux_state,
 | 
						rc = avc_has_perm_noaudit(&selinux_state,
 | 
				
			||||||
				  sid, isec->sid, isec->sclass, perms,
 | 
									  sid, isec->sid, isec->sclass, perms, 0,
 | 
				
			||||||
				  no_block ? AVC_NONBLOCKING : 0,
 | 
					 | 
				
			||||||
				  &avd);
 | 
									  &avd);
 | 
				
			||||||
	audited = avc_audit_required(perms, &avd, rc,
 | 
						audited = avc_audit_required(perms, &avd, rc,
 | 
				
			||||||
				     from_access ? FILE__AUDIT_ACCESS : 0,
 | 
									     from_access ? FILE__AUDIT_ACCESS : 0,
 | 
				
			||||||
| 
						 | 
					@ -3218,10 +3213,6 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 | 
				
			||||||
	if (likely(!audited))
 | 
						if (likely(!audited))
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* fall back to ref-walk if we have to generate audit */
 | 
					 | 
				
			||||||
	if (no_block)
 | 
					 | 
				
			||||||
		return -ECHILD;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc2 = audit_inode_permission(inode, perms, audited, denied, rc);
 | 
						rc2 = audit_inode_permission(inode, perms, audited, denied, rc);
 | 
				
			||||||
	if (rc2)
 | 
						if (rc2)
 | 
				
			||||||
		return rc2;
 | 
							return rc2;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,9 +134,6 @@ static inline int avc_audit(struct selinux_state *state,
 | 
				
			||||||
	audited = avc_audit_required(requested, avd, result, 0, &denied);
 | 
						audited = avc_audit_required(requested, avd, result, 0, &denied);
 | 
				
			||||||
	if (likely(!audited))
 | 
						if (likely(!audited))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	/* fall back to ref-walk if we have to generate audit */
 | 
					 | 
				
			||||||
	if (flags & MAY_NOT_BLOCK)
 | 
					 | 
				
			||||||
		return -ECHILD;
 | 
					 | 
				
			||||||
	return slow_avc_audit(state, ssid, tsid, tclass,
 | 
						return slow_avc_audit(state, ssid, tsid, tclass,
 | 
				
			||||||
			      requested, audited, denied, result,
 | 
								      requested, audited, denied, result,
 | 
				
			||||||
			      a);
 | 
								      a);
 | 
				
			||||||
| 
						 | 
					@ -144,7 +141,6 @@ static inline int avc_audit(struct selinux_state *state,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AVC_STRICT 1 /* Ignore permissive mode. */
 | 
					#define AVC_STRICT 1 /* Ignore permissive mode. */
 | 
				
			||||||
#define AVC_EXTENDED_PERMS 2	/* update extended permissions */
 | 
					#define AVC_EXTENDED_PERMS 2	/* update extended permissions */
 | 
				
			||||||
#define AVC_NONBLOCKING    4	/* non blocking */
 | 
					 | 
				
			||||||
int avc_has_perm_noaudit(struct selinux_state *state,
 | 
					int avc_has_perm_noaudit(struct selinux_state *state,
 | 
				
			||||||
			 u32 ssid, u32 tsid,
 | 
								 u32 ssid, u32 tsid,
 | 
				
			||||||
			 u16 tclass, u32 requested,
 | 
								 u16 tclass, u32 requested,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue