Smack: correct behavior in the mmap hook
[pandora-kernel.git] / security / smack / smack_lsm.c
index 123a499..92cb715 100644 (file)
@@ -1109,38 +1109,6 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
        return rc;
 }
 
-/**
- * smk_mmap_list_check - the mmap check
- * @sub: subject label
- * @obj: object label
- * @access: access mode
- * @local: the task specific rule list
- *
- * Returns 0 if acces is permitted, -EACCES otherwise
- */
-static int smk_mmap_list_check(char *sub, char *obj, int access,
-                               struct list_head *local)
-{
-       int may;
-
-       /*
-        * If there is not a global rule that
-        * allows access say no.
-        */
-       may = smk_access_entry(sub, obj, &smack_rule_list);
-       if (may == -ENOENT || (may & access) != access)
-               return -EACCES;
-       /*
-        * If there is a task local rule that
-        * denies access say no.
-        */
-       may = smk_access_entry(sub, obj, local);
-       if (may != -ENOENT && (may & access) != access)
-               return -EACCES;
-
-       return 0;
-}
-
 /**
  * smack_file_mmap :
  * Check permissions for a mmap operation.  The @file may be NULL, e.g.
@@ -1160,8 +1128,12 @@ static int smack_file_mmap(struct file *file,
        struct task_smack *tsp;
        char *sp;
        char *msmack;
+       char *osmack;
        struct inode_smack *isp;
        struct dentry *dp;
+       int may;
+       int mmay;
+       int tmay;
        int rc;
 
        /* do DAC check on address space usage */
@@ -1199,16 +1171,57 @@ static int smack_file_mmap(struct file *file,
        list_for_each_entry_rcu(srp, &smack_rule_list, list) {
                if (srp->smk_subject != sp)
                        continue;
+
+               osmack = srp->smk_object;
                /*
                 * Matching labels always allows access.
                 */
-               if (msmack == srp->smk_object)
+               if (msmack == osmack)
+                       continue;
+               /*
+                * If there is a matching local rule take
+                * that into account as well.
+                */
+               may = smk_access_entry(srp->smk_subject, osmack,
+                                       &tsp->smk_rules);
+               if (may == -ENOENT)
+                       may = srp->smk_access;
+               else
+                       may &= srp->smk_access;
+               /*
+                * If may is zero the SMACK64MMAP subject can't
+                * possibly have less access.
+                */
+               if (may == 0)
                        continue;
 
-               rc = smk_mmap_list_check(msmack, srp->smk_object,
-                                        srp->smk_access, &tsp->smk_rules);
-               if (rc != 0)
+               /*
+                * Fetch the global list entry.
+                * If there isn't one a SMACK64MMAP subject
+                * can't have as much access as current.
+                */
+               mmay = smk_access_entry(msmack, osmack, &smack_rule_list);
+               if (mmay == -ENOENT) {
+                       rc = -EACCES;
                        break;
+               }
+               /*
+                * If there is a local entry it modifies the
+                * potential access, too.
+                */
+               tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules);
+               if (tmay != -ENOENT)
+                       mmay &= tmay;
+
+               /*
+                * If there is any access available to current that is
+                * not available to a SMACK64MMAP subject
+                * deny access.
+                */
+               if ((may | mmay) != may) {
+                       rc = -EACCES;
+                       break;
+               }
        }
 
        rcu_read_unlock();