Merge branch 'misc-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
[pandora-kernel.git] / security / integrity / evm / evm_crypto.c
index d49bb00..5dd5b14 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/module.h>
 #include <linux/crypto.h>
 #include <linux/xattr.h>
-#include <linux/scatterlist.h>
 #include <keys/encrypted-type.h>
+#include <crypto/hash.h>
 #include "evm.h"
 
 #define EVMKEY "evm-key"
 static unsigned char evmkey[MAX_KEY_SIZE];
 static int evmkey_len = MAX_KEY_SIZE;
 
-static int init_desc(struct hash_desc *desc)
+struct crypto_shash *hmac_tfm;
+
+static struct shash_desc *init_desc(void)
 {
        int rc;
+       struct shash_desc *desc;
 
-       desc->tfm = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(desc->tfm)) {
-               pr_info("Can not allocate %s (reason: %ld)\n",
-                       evm_hmac, PTR_ERR(desc->tfm));
-               rc = PTR_ERR(desc->tfm);
-               return rc;
+       if (hmac_tfm == NULL) {
+               hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(hmac_tfm)) {
+                       pr_err("Can not allocate %s (reason: %ld)\n",
+                              evm_hmac, PTR_ERR(hmac_tfm));
+                       rc = PTR_ERR(hmac_tfm);
+                       hmac_tfm = NULL;
+                       return ERR_PTR(rc);
+               }
        }
-       desc->flags = 0;
-       rc = crypto_hash_setkey(desc->tfm, evmkey, evmkey_len);
+
+       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
+                       GFP_KERNEL);
+       if (!desc)
+               return ERR_PTR(-ENOMEM);
+
+       desc->tfm = hmac_tfm;
+       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
        if (rc)
                goto out;
-       rc = crypto_hash_init(desc);
+       rc = crypto_shash_init(desc);
 out:
-       if (rc)
-               crypto_free_hash(desc->tfm);
-       return rc;
+       if (rc) {
+               kfree(desc);
+               return ERR_PTR(rc);
+       }
+       return desc;
 }
 
 /* Protect against 'cutting & pasting' security.evm xattr, include inode
@@ -53,7 +69,7 @@ out:
  * (Additional directory/file metadata needs to be added for more complete
  * protection.)
  */
-static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
+static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
                          char *digest)
 {
        struct h_misc {
@@ -63,7 +79,6 @@ static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
                gid_t gid;
                umode_t mode;
        } hmac_misc;
-       struct scatterlist sg[1];
 
        memset(&hmac_misc, 0, sizeof hmac_misc);
        hmac_misc.ino = inode->i_ino;
@@ -71,9 +86,8 @@ static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
        hmac_misc.uid = inode->i_uid;
        hmac_misc.gid = inode->i_gid;
        hmac_misc.mode = inode->i_mode;
-       sg_init_one(sg, &hmac_misc, sizeof hmac_misc);
-       crypto_hash_update(desc, sg, sizeof hmac_misc);
-       crypto_hash_final(desc, digest);
+       crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc);
+       crypto_shash_final(desc, digest);
 }
 
 /*
@@ -88,8 +102,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
                  char *digest)
 {
        struct inode *inode = dentry->d_inode;
-       struct hash_desc desc;
-       struct scatterlist sg[1];
+       struct shash_desc *desc;
        char **xattrname;
        size_t xattr_size = 0;
        char *xattr_value = NULL;
@@ -98,17 +111,17 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 
        if (!inode->i_op || !inode->i_op->getxattr)
                return -EOPNOTSUPP;
-       error = init_desc(&desc);
-       if (error)
-               return error;
+       desc = init_desc();
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
 
        error = -ENODATA;
        for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
                if ((req_xattr_name && req_xattr_value)
                    && !strcmp(*xattrname, req_xattr_name)) {
                        error = 0;
-                       sg_init_one(sg, req_xattr_value, req_xattr_value_len);
-                       crypto_hash_update(&desc, sg, req_xattr_value_len);
+                       crypto_shash_update(desc, (const u8 *)req_xattr_value,
+                                            req_xattr_value_len);
                        continue;
                }
                size = vfs_getxattr_alloc(dentry, *xattrname,
@@ -122,13 +135,13 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 
                error = 0;
                xattr_size = size;
-               sg_init_one(sg, xattr_value, xattr_size);
-               crypto_hash_update(&desc, sg, xattr_size);
+               crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
        }
-       hmac_add_misc(&desc, inode, digest);
-       kfree(xattr_value);
+       hmac_add_misc(desc, inode, digest);
+
 out:
-       crypto_free_hash(desc.tfm);
+       kfree(xattr_value);
+       kfree(desc);
        return error;
 }
 
@@ -141,19 +154,39 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
                        const char *xattr_value, size_t xattr_value_len)
 {
        struct inode *inode = dentry->d_inode;
-       u8 hmac[SHA1_DIGEST_SIZE];
+       struct evm_ima_xattr_data xattr_data;
        int rc = 0;
 
        rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
-                          xattr_value_len, hmac);
-       if (rc == 0)
+                          xattr_value_len, xattr_data.digest);
+       if (rc == 0) {
+               xattr_data.type = EVM_XATTR_HMAC;
                rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
-                                          hmac, SHA1_DIGEST_SIZE, 0);
+                                          &xattr_data,
+                                          sizeof(xattr_data), 0);
+       }
        else if (rc == -ENODATA)
                rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
        return rc;
 }
 
+int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
+                 char *hmac_val)
+{
+       struct shash_desc *desc;
+
+       desc = init_desc();
+       if (IS_ERR(desc)) {
+               printk(KERN_INFO "init_desc failed\n");
+               return PTR_ERR(desc);
+       }
+
+       crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len);
+       hmac_add_misc(desc, inode, hmac_val);
+       kfree(desc);
+       return 0;
+}
+
 /*
  * Get the key from the TPM for the SHA1-HMAC
  */