SELinux: check seqno when updating an avc_node

The avc update node callbacks do not check the seqno of the caller with the
seqno of the node found.  It is possible that a policy change could happen
(although almost impossibly unlikely) in which a permissive or
permissive_domain decision is not valid for the entry found.  Simply pass
and check that the seqno of the caller and the seqno of the node found
match.

Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by:  Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index eb41f43..0d00f48 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -742,13 +742,15 @@
  * @event : Updating event
  * @perms : Permission mask bits
  * @ssid,@tsid,@tclass : identifier of an AVC entry
+ * @seqno : sequence number when decision was made
  *
  * if a valid AVC entry doesn't exist,this function returns -ENOENT.
  * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
  * otherwise, this function update the AVC entry. The original AVC-entry object
  * will release later by RCU.
  */
-static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
+			   u32 seqno)
 {
 	int hvalue, rc = 0;
 	unsigned long flag;
@@ -767,7 +769,8 @@
 	list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {
 		if (ssid == pos->ae.ssid &&
 		    tsid == pos->ae.tsid &&
-		    tclass == pos->ae.tclass){
+		    tclass == pos->ae.tclass &&
+		    seqno == pos->ae.avd.seqno){
 			orig = pos;
 			break;
 		}
@@ -908,7 +911,7 @@
 			rc = -EACCES;
 		else if (!selinux_enforcing || security_permissive_sid(ssid))
 			avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
-					tsid, tclass);
+					tsid, tclass, p_ae->avd.seqno);
 		else
 			rc = -EACCES;
 	}