]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Feb 2013 16:18:12 +0000 (08:18 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Feb 2013 16:18:12 +0000 (08:18 -0800)
Pull security subsystem updates from James Morris:
 "This is basically a maintenance update for the TPM driver and EVM/IMA"

Fix up conflicts in lib/digsig.c and security/integrity/ima/ima_main.c

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (45 commits)
  tpm/ibmvtpm: build only when IBM pseries is configured
  ima: digital signature verification using asymmetric keys
  ima: rename hash calculation functions
  ima: use new crypto_shash API instead of old crypto_hash
  ima: add policy support for file system uuid
  evm: add file system uuid to EVM hmac
  tpm_tis: check pnp_acpi_device return code
  char/tpm/tpm_i2c_stm_st33: drop temporary variable for return value
  char/tpm/tpm_i2c_stm_st33: remove dead assignment in tpm_st33_i2c_probe
  char/tpm/tpm_i2c_stm_st33: Remove __devexit attribute
  char/tpm/tpm_i2c_stm_st33: Don't use memcpy for one byte assignment
  tpm_i2c_stm_st33: removed unused variables/code
  TPM: Wait for TPM_ACCESS tpmRegValidSts to go high at startup
  tpm: Fix cancellation of TPM commands (interrupt mode)
  tpm: Fix cancellation of TPM commands (polling mode)
  tpm: Store TPM vendor ID
  TPM: Work around buggy TPMs that block during continue self test
  tpm_i2c_stm_st33: fix oops when i2c client is unavailable
  char/tpm: Use struct dev_pm_ops for power management
  TPM: STMicroelectronics ST33 I2C BUILD STUFF
  ...

1  2 
lib/digsig.c
security/integrity/evm/evm_crypto.c
security/integrity/ima/ima.h
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c

diff --combined lib/digsig.c
index dc2be7ed1765b0dc3675c97b2cf862dc969dcd90,0103c5b9b80294ea793df46163789bf7745ec2b9..2f31e6a45f0af3f4e4bccd38aeb1d8324c72eeff
  
  static struct crypto_shash *shash;
  
- static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg,
-                       unsigned long  msglen,
-                       unsigned long  modulus_bitlen,
-                       unsigned char *out,
-                       unsigned long *outlen)
+ static const char *pkcs_1_v1_5_decode_emsa(const unsigned char *msg,
+                                               unsigned long  msglen,
+                                               unsigned long  modulus_bitlen,
+                                               unsigned long *outlen)
  {
        unsigned long modulus_len, ps_len, i;
  
  
        /* test message size */
        if ((msglen > modulus_len) || (modulus_len < 11))
-               return -EINVAL;
+               return NULL;
  
        /* separate encoded message */
-       if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1))
-               return -EINVAL;
+       if (msg[0] != 0x00 || msg[1] != 0x01)
+               return NULL;
  
        for (i = 2; i < modulus_len - 1; i++)
                if (msg[i] != 0xFF)
        if (msg[i] != 0)
                /* There was no octet with hexadecimal value 0x00
                to separate ps from m. */
-               return -EINVAL;
+               return NULL;
  
        ps_len = i - 2;
  
-       if (*outlen < (msglen - (2 + ps_len + 1))) {
-               *outlen = msglen - (2 + ps_len + 1);
-               return -EOVERFLOW;
-       }
        *outlen = (msglen - (2 + ps_len + 1));
-       memcpy(out, &msg[2 + ps_len + 1], *outlen);
  
-       return 0;
+       return msg + 2 + ps_len + 1;
  }
  
  /*
@@@ -83,7 -76,8 +76,8 @@@ static int digsig_verify_rsa(struct ke
        unsigned long mlen, mblen;
        unsigned nret, l;
        int head, i;
-       unsigned char *out1 = NULL, *out2 = NULL;
+       unsigned char *out1 = NULL;
+       const char *m;
        MPI in = NULL, res = NULL, pkey[2];
        uint8_t *p, *datap, *endp;
        struct user_key_payload *ukp;
        }
  
        mblen = mpi_get_nbits(pkey[0]);
-       mlen = (mblen + 7)/8;
+       mlen = DIV_ROUND_UP(mblen, 8);
  
        if (mlen == 0)
                goto err;
        if (!out1)
                goto err;
  
-       out2 = kzalloc(mlen, GFP_KERNEL);
-       if (!out2)
-               goto err;
        nret = siglen;
        in = mpi_read_from_buffer(sig, &nret);
        if (!in)
        memset(out1, 0, head);
        memcpy(out1 + head, p, l);
  
-       err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len);
-       if (err)
-               goto err;
 +      kfree(p);
 +
+       m = pkcs_1_v1_5_decode_emsa(out1, len, mblen, &len);
  
-       if (len != hlen || memcmp(out2, h, hlen))
+       if (!m || len != hlen || memcmp(m, h, hlen))
                err = -EINVAL;
  
  err:
        mpi_free(in);
        mpi_free(res);
        kfree(out1);
-       kfree(out2);
        while (--i >= 0)
                mpi_free(pkey[i]);
  err1:
index 7dd538ef5b8319e645465eb62294158f3dbe271a,ff8e2abf8f2114bd4fc106e0ff5d13cd771f296e..3bab89eb21d608b1123b97188234137db83869b8
@@@ -110,6 -110,9 +110,9 @@@ static void hmac_add_misc(struct shash_
        hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
        hmac_misc.mode = inode->i_mode;
        crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc);
+       if (evm_hmac_version > 1)
+               crypto_shash_update(desc, inode->i_sb->s_uuid,
+                                   sizeof(inode->i_sb->s_uuid));
        crypto_shash_final(desc, digest);
  }
  
@@@ -205,9 -208,9 +208,9 @@@ int evm_update_evmxattr(struct dentry *
                rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
                                           &xattr_data,
                                           sizeof(xattr_data), 0);
 -      }
 -      else if (rc == -ENODATA)
 +      } else if (rc == -ENODATA && inode->i_op->removexattr) {
                rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
 +      }
        return rc;
  }
  
index 079a85dc37b2ba9fd7d649a1a0da0e2843a9252c,6e69697fd530051c4bc3ab4af71dee6aad982fb2..a41c9c18e5e0706498d44a26e3ece7d49f307e4c
@@@ -84,11 -84,12 +84,12 @@@ void ima_fs_cleanup(void)
  int ima_inode_alloc(struct inode *inode);
  int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                           const char *op, struct inode *inode);
- int ima_calc_hash(struct file *file, char *digest);
- int ima_calc_template_hash(int template_len, void *template, char *digest);
+ int ima_calc_file_hash(struct file *file, char *digest);
+ int ima_calc_buffer_hash(const void *data, int len, char *digest);
  int ima_calc_boot_aggregate(char *digest);
  void ima_add_violation(struct inode *inode, const unsigned char *filename,
                       const char *op, const char *cause);
+ int ima_init_crypto(void);
  
  /*
   * used to protect h_table and sha_table
@@@ -119,6 -120,7 +120,7 @@@ void ima_audit_measurement(struct integ
  int ima_store_template(struct ima_template_entry *entry, int violation,
                       struct inode *inode);
  void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show);
+ const char *ima_d_path(struct path *path, char **pathbuf);
  
  /* rbtree tree calls to lookup, insert, delete
   * integrity data associated with an inode.
@@@ -127,7 -129,7 +129,7 @@@ struct integrity_iint_cache *integrity_
  struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
  
  /* IMA policy related functions */
- enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
+ enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
  
  int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                     int flags);
@@@ -139,16 -141,18 +141,19 @@@ void ima_delete_rules(void)
  /* Appraise integrity measurements */
  #define IMA_APPRAISE_ENFORCE  0x01
  #define IMA_APPRAISE_FIX      0x02
 +#define IMA_APPRAISE_MODULES  0x04
  
  #ifdef CONFIG_IMA_APPRAISE
- int ima_appraise_measurement(struct integrity_iint_cache *iint,
+ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                             struct file *file, const unsigned char *filename);
  int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
  void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
+ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
+                                          int func);
  
  #else
- static inline int ima_appraise_measurement(struct integrity_iint_cache *iint,
+ static inline int ima_appraise_measurement(int func,
+                                          struct integrity_iint_cache *iint,
                                           struct file *file,
                                           const unsigned char *filename)
  {
@@@ -165,6 -169,12 +170,12 @@@ static inline void ima_update_xattr(str
                                    struct file *file)
  {
  }
+ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache
+                                                        *iint, int func)
+ {
+       return INTEGRITY_UNKNOWN;
+ }
  #endif
  
  /* LSM based policy rules require audit */
index dba965de90d3f838c82e1a93202bf585fa1e5cd6,3e751a9743a1896365b8ef730b77603074e2ee91..5127afcc4b8982a4353b87ccc5f4542ec7862f39
@@@ -61,7 -61,8 +61,8 @@@ static void ima_rdwr_violation_check(st
        fmode_t mode = file->f_mode;
        int must_measure;
        bool send_tomtou = false, send_writers = false;
-       unsigned char *pathname = NULL, *pathbuf = NULL;
+       char *pathbuf = NULL;
+       const char *pathname;
  
        if (!S_ISREG(inode->i_mode) || !ima_initialized)
                return;
@@@ -86,22 -87,15 +87,15 @@@ out
        if (!send_tomtou && !send_writers)
                return;
  
-       /* We will allow 11 spaces for ' (deleted)' to be appended */
-       pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
-       if (pathbuf) {
-               pathname = d_path(&file->f_path, pathbuf, PATH_MAX + 11);
-               if (IS_ERR(pathname))
-                       pathname = NULL;
-               else if (strlen(pathname) > IMA_EVENT_NAME_LEN_MAX)
-                       pathname = NULL;
-       }
+       pathname = ima_d_path(&file->f_path, &pathbuf);
+       if (!pathname || strlen(pathname) > IMA_EVENT_NAME_LEN_MAX)
+               pathname = dentry->d_name.name;
        if (send_tomtou)
-               ima_add_violation(inode,
-                                 !pathname ? dentry->d_name.name : pathname,
+               ima_add_violation(inode, pathname,
                                  "invalid_pcr", "ToMToU");
        if (send_writers)
-               ima_add_violation(inode,
-                                 !pathname ? dentry->d_name.name : pathname,
+               ima_add_violation(inode, pathname,
                                  "invalid_pcr", "open_writers");
        kfree(pathbuf);
  }
@@@ -145,25 -139,31 +139,31 @@@ void ima_file_free(struct file *file
        ima_check_last_writer(iint, inode, file);
  }
  
- static int process_measurement(struct file *file, const unsigned char *filename,
+ static int process_measurement(struct file *file, const char *filename,
                               int mask, int function)
  {
        struct inode *inode = file->f_dentry->d_inode;
        struct integrity_iint_cache *iint;
-       unsigned char *pathname = NULL, *pathbuf = NULL;
-       int rc = -ENOMEM, action, must_appraise;
+       char *pathbuf = NULL;
+       const char *pathname = NULL;
+       int rc = -ENOMEM, action, must_appraise, _func;
  
        if (!ima_initialized || !S_ISREG(inode->i_mode))
                return 0;
  
-       /* Determine if in appraise/audit/measurement policy,
-        * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask.  */
+       /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
+        * bitmask based on the appraise/audit/measurement policy.
+        * Included is the appraise submask.
+        */
        action = ima_get_action(inode, mask, function);
        if (!action)
                return 0;
  
        must_appraise = action & IMA_APPRAISE;
  
+       /*  Is the appraise rule hook specific?  */
+       _func = (action & IMA_FILE_APPRAISE) ? FILE_CHECK : function;
        mutex_lock(&inode->i_mutex);
  
        iint = integrity_inode_get(inode);
                goto out;
  
        /* Determine if already appraised/measured based on bitmask
-        * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED,
-        *  IMA_AUDIT, IMA_AUDITED) */
+        * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
+        *  IMA_AUDIT, IMA_AUDITED)
+        */
        iint->flags |= action;
+       action &= IMA_DO_MASK;
        action &= ~((iint->flags & IMA_DONE_MASK) >> 1);
  
        /* Nothing to do, just return existing appraised status */
        if (!action) {
-               if (iint->flags & IMA_APPRAISED)
-                       rc = iint->ima_status;
-               goto out;
+               if (must_appraise)
+                       rc = ima_get_cache_status(iint, _func);
+               goto out_digsig;
        }
  
        rc = ima_collect_measurement(iint, file);
        if (rc != 0)
-               goto out;
+               goto out_digsig;
+       if (function != BPRM_CHECK)
+               pathname = ima_d_path(&file->f_path, &pathbuf);
+       if (!pathname)
+               pathname = filename;
  
-       if (function != BPRM_CHECK) {
-               /* We will allow 11 spaces for ' (deleted)' to be appended */
-               pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
-               if (pathbuf) {
-                       pathname =
-                           d_path(&file->f_path, pathbuf, PATH_MAX + 11);
-                       if (IS_ERR(pathname))
-                               pathname = NULL;
-               }
-       }
        if (action & IMA_MEASURE)
-               ima_store_measurement(iint, file,
-                                     !pathname ? filename : pathname);
-       if (action & IMA_APPRAISE)
-               rc = ima_appraise_measurement(iint, file,
-                                             !pathname ? filename : pathname);
+               ima_store_measurement(iint, file, pathname);
+       if (action & IMA_APPRAISE_SUBMASK)
+               rc = ima_appraise_measurement(_func, iint, file, pathname);
        if (action & IMA_AUDIT)
-               ima_audit_measurement(iint, !pathname ? filename : pathname);
+               ima_audit_measurement(iint, pathname);
        kfree(pathbuf);
+ out_digsig:
+       if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
+               rc = -EACCES;
  out:
        mutex_unlock(&inode->i_mutex);
-       return (rc && must_appraise) ? -EACCES : 0;
+       if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
+               return -EACCES;
+       return 0;
  }
  
  /**
   * Measure files being mmapped executable based on the ima_must_measure()
   * policy decision.
   *
-  * Return 0 on success, an error code on failure.
-  * (Based on the results of appraise_measurement().)
+  * On success return 0.  On integrity appraisal error, assuming the file
+  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
   */
  int ima_file_mmap(struct file *file, unsigned long prot)
  {
-       int rc = 0;
-       if (!file)
-               return 0;
-       if (prot & PROT_EXEC)
-               rc = process_measurement(file, file->f_dentry->d_name.name,
-                                        MAY_EXEC, FILE_MMAP);
-       return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
+       if (file && (prot & PROT_EXEC))
+               return process_measurement(file, file->f_dentry->d_name.name,
+                                          MAY_EXEC, MMAP_CHECK);
+       return 0;
  }
  
  /**
   * So we can be certain that what we verify and measure here is actually
   * what is being executed.
   *
-  * Return 0 on success, an error code on failure.
-  * (Based on the results of appraise_measurement().)
+  * On success return 0.  On integrity appraisal error, assuming the file
+  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
   */
  int ima_bprm_check(struct linux_binprm *bprm)
  {
-       int rc;
-       rc = process_measurement(bprm->file,
+       return process_measurement(bprm->file,
                                 (strcmp(bprm->filename, bprm->interp) == 0) ?
                                 bprm->filename : bprm->interp,
                                 MAY_EXEC, BPRM_CHECK);
-       return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
  }
  
  /**
   *
   * Measure files based on the ima_must_measure() policy decision.
   *
-  * Always return 0 and audit dentry_open failures.
-  * (Return code will be based upon measurement appraisal.)
+  * On success return 0.  On integrity appraisal error, assuming the file
+  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
   */
  int ima_file_check(struct file *file, int mask)
  {
-       int rc;
        ima_rdwr_violation_check(file);
-       rc = process_measurement(file, file->f_dentry->d_name.name,
+       return process_measurement(file, file->f_dentry->d_name.name,
                                 mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
                                 FILE_CHECK);
-       return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
  }
  EXPORT_SYMBOL_GPL(ima_file_check);
  
   *
   * Measure/appraise kernel modules based on policy.
   *
-  * Always return 0 and audit dentry_open failures.
-  * Return code is based upon measurement appraisal.
+  * On success return 0.  On integrity appraisal error, assuming the file
+  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
   */
  int ima_module_check(struct file *file)
  {
-       int rc = 0;
 -      if (!file)
 -              return -EACCES; /* INTEGRITY_UNKNOWN */
 +      if (!file) {
-               if (ima_appraise & IMA_APPRAISE_MODULES) {
 +#ifndef CONFIG_MODULE_SIG_FORCE
-                       rc = -EACCES;   /* INTEGRITY_UNKNOWN */
++              if (ima_appraise & IMA_APPRAISE_MODULES)
++                      return -EACCES; /* INTEGRITY_UNKNOWN */
 +#endif
-               }
-       } else
-               rc = process_measurement(file, file->f_dentry->d_name.name,
-                                        MAY_EXEC, MODULE_CHECK);
-       return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
++              return 0;       /* We rely on module signature checking */
++      }
+       return process_measurement(file, file->f_dentry->d_name.name,
+                                  MAY_EXEC, MODULE_CHECK);
  }
  
  static int __init init_ima(void)
index 479fca940bb5552df6591723f09408c3325054f0,23f49e37a9578336669e4bc3f67f5b1a955c8f07..b27535a13a791f281d8686bec90fa043481d55d3
@@@ -16,6 -16,7 +16,7 @@@
  #include <linux/magic.h>
  #include <linux/parser.h>
  #include <linux/slab.h>
+ #include <linux/genhd.h>
  
  #include "ima.h"
  
@@@ -25,6 -26,7 +26,7 @@@
  #define IMA_FSMAGIC   0x0004
  #define IMA_UID               0x0008
  #define IMA_FOWNER    0x0010
+ #define IMA_FSUUID    0x0020
  
  #define UNKNOWN               0
  #define MEASURE               0x0001  /* same as IMA_MEASURE */
@@@ -45,10 -47,12 +47,12 @@@ struct ima_rule_entry 
        enum ima_hooks func;
        int mask;
        unsigned long fsmagic;
+       u8 fsuuid[16];
        kuid_t uid;
        kuid_t fowner;
        struct {
                void *rule;     /* LSM file metadata specific */
+               void *args_p;   /* audit value */
                int type;       /* audit type */
        } lsm[MAX_LSM_RULES];
  };
@@@ -74,7 -78,7 +78,7 @@@ static struct ima_rule_entry default_ru
        {.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
-       {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
+       {.action = MEASURE,.func = MMAP_CHECK,.mask = MAY_EXEC,
         .flags = IMA_FUNC | IMA_MASK},
        {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
         .flags = IMA_FUNC | IMA_MASK},
@@@ -119,6 -123,35 +123,35 @@@ static int __init default_appraise_poli
  }
  __setup("ima_appraise_tcb", default_appraise_policy_setup);
  
+ /* 
+  * Although the IMA policy does not change, the LSM policy can be
+  * reloaded, leaving the IMA LSM based rules referring to the old,
+  * stale LSM policy.
+  *
+  * Update the IMA LSM based rules to reflect the reloaded LSM policy. 
+  * We assume the rules still exist; and BUG_ON() if they don't.
+  */
+ static void ima_lsm_update_rules(void)
+ {
+       struct ima_rule_entry *entry, *tmp;
+       int result;
+       int i;
+       mutex_lock(&ima_rules_mutex);
+       list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+               for (i = 0; i < MAX_LSM_RULES; i++) {
+                       if (!entry->lsm[i].rule)
+                               continue;
+                       result = security_filter_rule_init(entry->lsm[i].type,
+                                                          Audit_equal,
+                                                          entry->lsm[i].args_p,
+                                                          &entry->lsm[i].rule);
+                       BUG_ON(!entry->lsm[i].rule);
+               }
+       }
+       mutex_unlock(&ima_rules_mutex);
+ }
  /**
   * ima_match_rules - determine whether an inode matches the measure rule.
   * @rule: a pointer to a rule
@@@ -142,6 -175,9 +175,9 @@@ static bool ima_match_rules(struct ima_
        if ((rule->flags & IMA_FSMAGIC)
            && rule->fsmagic != inode->i_sb->s_magic)
                return false;
+       if ((rule->flags & IMA_FSUUID) &&
+               memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid)))
+               return false;
        if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid))
                return false;
        if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid))
        for (i = 0; i < MAX_LSM_RULES; i++) {
                int rc = 0;
                u32 osid, sid;
+               int retried = 0;
  
                if (!rule->lsm[i].rule)
                        continue;
+ retry:
                switch (i) {
                case LSM_OBJ_USER:
                case LSM_OBJ_ROLE:
                default:
                        break;
                }
+               if ((rc < 0) && (!retried)) {
+                       retried = 1;
+                       ima_lsm_update_rules();
+                       goto retry;
+               } 
                if (!rc)
                        return false;
        }
        return true;
  }
  
+ /*
+  * In addition to knowing that we need to appraise the file in general,
+  * we need to differentiate between calling hooks, for hook specific rules.
+  */
+ static int get_subaction(struct ima_rule_entry *rule, int func)
+ {
+       if (!(rule->flags & IMA_FUNC))
+               return IMA_FILE_APPRAISE;
+       switch(func) {
+       case MMAP_CHECK:
+               return IMA_MMAP_APPRAISE;
+       case BPRM_CHECK:
+               return IMA_BPRM_APPRAISE;
+       case MODULE_CHECK:
+               return IMA_MODULE_APPRAISE;
+       case FILE_CHECK:
+       default:
+               return IMA_FILE_APPRAISE;
+       }
+ }
  /**
   * ima_match_policy - decision based on LSM and other conditions
   * @inode: pointer to an inode for which the policy decision is being made
@@@ -209,7 -273,12 +273,12 @@@ int ima_match_policy(struct inode *inod
                if (!ima_match_rules(entry, inode, func, mask))
                        continue;
  
+               action |= entry->flags & IMA_ACTION_FLAGS;
                action |= entry->action & IMA_DO_MASK;
+               if (entry->action & IMA_APPRAISE)
+                       action |= get_subaction(entry, func);
                if (entry->action & IMA_DO_MASK)
                        actmask &= ~(entry->action | entry->action << 1);
                else
@@@ -282,7 -351,8 +351,8 @@@ enum 
        Opt_audit,
        Opt_obj_user, Opt_obj_role, Opt_obj_type,
        Opt_subj_user, Opt_subj_role, Opt_subj_type,
-       Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner
+       Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner,
+       Opt_appraise_type, Opt_fsuuid
  };
  
  static match_table_t policy_tokens = {
        {Opt_func, "func=%s"},
        {Opt_mask, "mask=%s"},
        {Opt_fsmagic, "fsmagic=%s"},
+       {Opt_fsuuid, "fsuuid=%s"},
        {Opt_uid, "uid=%s"},
        {Opt_fowner, "fowner=%s"},
+       {Opt_appraise_type, "appraise_type=%s"},
        {Opt_err, NULL}
  };
  
  static int ima_lsm_rule_init(struct ima_rule_entry *entry,
-                            char *args, int lsm_rule, int audit_type)
+                            substring_t *args, int lsm_rule, int audit_type)
  {
        int result;
  
        if (entry->lsm[lsm_rule].rule)
                return -EINVAL;
  
+       entry->lsm[lsm_rule].args_p = match_strdup(args);
+       if (!entry->lsm[lsm_rule].args_p)
+               return -ENOMEM;
        entry->lsm[lsm_rule].type = audit_type;
        result = security_filter_rule_init(entry->lsm[lsm_rule].type,
-                                          Audit_equal, args,
+                                          Audit_equal,
+                                          entry->lsm[lsm_rule].args_p,
                                           &entry->lsm[lsm_rule].rule);
-       if (!entry->lsm[lsm_rule].rule)
+       if (!entry->lsm[lsm_rule].rule) {
+               kfree(entry->lsm[lsm_rule].args_p);
                return -EINVAL;
+       }
        return result;
  }
  
@@@ -404,8 -484,9 +484,9 @@@ static int ima_parse_rule(char *rule, s
                                entry->func = FILE_CHECK;
                        else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
                                entry->func = MODULE_CHECK;
-                       else if (strcmp(args[0].from, "FILE_MMAP") == 0)
-                               entry->func = FILE_MMAP;
+                       else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
+                               || (strcmp(args[0].from, "MMAP_CHECK") == 0))
+                               entry->func = MMAP_CHECK;
                        else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
                                entry->func = BPRM_CHECK;
                        else
                        if (!result)
                                entry->flags |= IMA_FSMAGIC;
                        break;
+               case Opt_fsuuid:
+                       ima_log_string(ab, "fsuuid", args[0].from);
+                       if (memchr_inv(entry->fsuuid, 0x00,
+                           sizeof(entry->fsuuid))) {
+                               result = -EINVAL;
+                               break;
+                       }
+                       part_pack_uuid(args[0].from, entry->fsuuid);
+                       entry->flags |= IMA_FSUUID;
+                       result = 0;
+                       break;
                case Opt_uid:
                        ima_log_string(ab, "uid", args[0].from);
  
                        break;
                case Opt_obj_user:
                        ima_log_string(ab, "obj_user", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_OBJ_USER,
                                                   AUDIT_OBJ_USER);
                        break;
                case Opt_obj_role:
                        ima_log_string(ab, "obj_role", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_OBJ_ROLE,
                                                   AUDIT_OBJ_ROLE);
                        break;
                case Opt_obj_type:
                        ima_log_string(ab, "obj_type", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_OBJ_TYPE,
                                                   AUDIT_OBJ_TYPE);
                        break;
                case Opt_subj_user:
                        ima_log_string(ab, "subj_user", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_SUBJ_USER,
                                                   AUDIT_SUBJ_USER);
                        break;
                case Opt_subj_role:
                        ima_log_string(ab, "subj_role", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_SUBJ_ROLE,
                                                   AUDIT_SUBJ_ROLE);
                        break;
                case Opt_subj_type:
                        ima_log_string(ab, "subj_type", args[0].from);
-                       result = ima_lsm_rule_init(entry, args[0].from,
+                       result = ima_lsm_rule_init(entry, args,
                                                   LSM_SUBJ_TYPE,
                                                   AUDIT_SUBJ_TYPE);
                        break;
+               case Opt_appraise_type:
+                       if (entry->action != APPRAISE) {
+                               result = -EINVAL;
+                               break;
+                       }
+                       ima_log_string(ab, "appraise_type", args[0].from);
+                       if ((strcmp(args[0].from, "imasig")) == 0)
+                               entry->flags |= IMA_DIGSIG_REQUIRED;
+                       else
+                               result = -EINVAL;
+                       break;
                case Opt_err:
                        ima_log_string(ab, "UNKNOWN", p);
                        result = -EINVAL;
        }
        if (!result && (entry->action == UNKNOWN))
                result = -EINVAL;
 -
 +      else if (entry->func == MODULE_CHECK)
 +              ima_appraise |= IMA_APPRAISE_MODULES;
        audit_log_format(ab, "res=%d", !result);
        audit_log_end(ab);
        return result;
@@@ -590,9 -695,13 +696,13 @@@ ssize_t ima_parse_add_rule(char *rule
  void ima_delete_rules(void)
  {
        struct ima_rule_entry *entry, *tmp;
+       int i;
  
        mutex_lock(&ima_rules_mutex);
        list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+               for (i = 0; i < MAX_LSM_RULES; i++)
+                       kfree(entry->lsm[i].args_p);
                list_del(&entry->list);
                kfree(entry);
        }