linux/security/integrity/evm/evm_crypto.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-2010 IBM Corporation
   3 *
   4 * Authors:
   5 * Mimi Zohar <zohar@us.ibm.com>
   6 * Kylene Hall <kjhall@us.ibm.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation, version 2 of the License.
  11 *
  12 * File: evm_crypto.c
  13 *       Using root's kernel master key (kmk), calculate the HMAC
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/crypto.h>
  18#include <linux/xattr.h>
  19#include <keys/encrypted-type.h>
  20#include <crypto/hash.h>
  21#include "evm.h"
  22
  23#define EVMKEY "evm-key"
  24#define MAX_KEY_SIZE 128
  25static unsigned char evmkey[MAX_KEY_SIZE];
  26static int evmkey_len = MAX_KEY_SIZE;
  27
  28struct crypto_shash *hmac_tfm;
  29struct crypto_shash *hash_tfm;
  30
  31static DEFINE_MUTEX(mutex);
  32
  33static struct shash_desc *init_desc(char type)
  34{
  35        long rc;
  36        char *algo;
  37        struct crypto_shash **tfm;
  38        struct shash_desc *desc;
  39
  40        if (type == EVM_XATTR_HMAC) {
  41                tfm = &hmac_tfm;
  42                algo = evm_hmac;
  43        } else {
  44                tfm = &hash_tfm;
  45                algo = evm_hash;
  46        }
  47
  48        if (*tfm == NULL) {
  49                mutex_lock(&mutex);
  50                if (*tfm)
  51                        goto out;
  52                *tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
  53                if (IS_ERR(*tfm)) {
  54                        rc = PTR_ERR(*tfm);
  55                        pr_err("Can not allocate %s (reason: %ld)\n", algo, rc);
  56                        *tfm = NULL;
  57                        mutex_unlock(&mutex);
  58                        return ERR_PTR(rc);
  59                }
  60                if (type == EVM_XATTR_HMAC) {
  61                        rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len);
  62                        if (rc) {
  63                                crypto_free_shash(*tfm);
  64                                *tfm = NULL;
  65                                mutex_unlock(&mutex);
  66                                return ERR_PTR(rc);
  67                        }
  68                }
  69out:
  70                mutex_unlock(&mutex);
  71        }
  72
  73        desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
  74                        GFP_KERNEL);
  75        if (!desc)
  76                return ERR_PTR(-ENOMEM);
  77
  78        desc->tfm = *tfm;
  79        desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
  80
  81        rc = crypto_shash_init(desc);
  82        if (rc) {
  83                kfree(desc);
  84                return ERR_PTR(rc);
  85        }
  86        return desc;
  87}
  88
  89/* Protect against 'cutting & pasting' security.evm xattr, include inode
  90 * specific info.
  91 *
  92 * (Additional directory/file metadata needs to be added for more complete
  93 * protection.)
  94 */
  95static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
  96                          char *digest)
  97{
  98        struct h_misc {
  99                unsigned long ino;
 100                __u32 generation;
 101                uid_t uid;
 102                gid_t gid;
 103                umode_t mode;
 104        } hmac_misc;
 105
 106        memset(&hmac_misc, 0, sizeof hmac_misc);
 107        hmac_misc.ino = inode->i_ino;
 108        hmac_misc.generation = inode->i_generation;
 109        hmac_misc.uid = inode->i_uid;
 110        hmac_misc.gid = inode->i_gid;
 111        hmac_misc.mode = inode->i_mode;
 112        crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc);
 113        crypto_shash_final(desc, digest);
 114}
 115
 116/*
 117 * Calculate the HMAC value across the set of protected security xattrs.
 118 *
 119 * Instead of retrieving the requested xattr, for performance, calculate
 120 * the hmac using the requested xattr value. Don't alloc/free memory for
 121 * each xattr, but attempt to re-use the previously allocated memory.
 122 */
 123static int evm_calc_hmac_or_hash(struct dentry *dentry,
 124                                const char *req_xattr_name,
 125                                const char *req_xattr_value,
 126                                size_t req_xattr_value_len,
 127                                char type, char *digest)
 128{
 129        struct inode *inode = dentry->d_inode;
 130        struct shash_desc *desc;
 131        char **xattrname;
 132        size_t xattr_size = 0;
 133        char *xattr_value = NULL;
 134        int error;
 135        int size;
 136
 137        if (!inode->i_op || !inode->i_op->getxattr)
 138                return -EOPNOTSUPP;
 139        desc = init_desc(type);
 140        if (IS_ERR(desc))
 141                return PTR_ERR(desc);
 142
 143        error = -ENODATA;
 144        for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
 145                if ((req_xattr_name && req_xattr_value)
 146                    && !strcmp(*xattrname, req_xattr_name)) {
 147                        error = 0;
 148                        crypto_shash_update(desc, (const u8 *)req_xattr_value,
 149                                             req_xattr_value_len);
 150                        continue;
 151                }
 152                size = vfs_getxattr_alloc(dentry, *xattrname,
 153                                          &xattr_value, xattr_size, GFP_NOFS);
 154                if (size == -ENOMEM) {
 155                        error = -ENOMEM;
 156                        goto out;
 157                }
 158                if (size < 0)
 159                        continue;
 160
 161                error = 0;
 162                xattr_size = size;
 163                crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
 164        }
 165        hmac_add_misc(desc, inode, digest);
 166
 167out:
 168        kfree(xattr_value);
 169        kfree(desc);
 170        return error;
 171}
 172
 173int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 174                  const char *req_xattr_value, size_t req_xattr_value_len,
 175                  char *digest)
 176{
 177        return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
 178                                req_xattr_value_len, EVM_XATTR_HMAC, digest);
 179}
 180
 181int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
 182                  const char *req_xattr_value, size_t req_xattr_value_len,
 183                  char *digest)
 184{
 185        return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
 186                                req_xattr_value_len, IMA_XATTR_DIGEST, digest);
 187}
 188
 189/*
 190 * Calculate the hmac and update security.evm xattr
 191 *
 192 * Expects to be called with i_mutex locked.
 193 */
 194int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
 195                        const char *xattr_value, size_t xattr_value_len)
 196{
 197        struct inode *inode = dentry->d_inode;
 198        struct evm_ima_xattr_data xattr_data;
 199        int rc = 0;
 200
 201        rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
 202                           xattr_value_len, xattr_data.digest);
 203        if (rc == 0) {
 204                xattr_data.type = EVM_XATTR_HMAC;
 205                rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
 206                                           &xattr_data,
 207                                           sizeof(xattr_data), 0);
 208        }
 209        else if (rc == -ENODATA)
 210                rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
 211        return rc;
 212}
 213
 214int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
 215                  char *hmac_val)
 216{
 217        struct shash_desc *desc;
 218
 219        desc = init_desc(EVM_XATTR_HMAC);
 220        if (IS_ERR(desc)) {
 221                printk(KERN_INFO "init_desc failed\n");
 222                return PTR_ERR(desc);
 223        }
 224
 225        crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len);
 226        hmac_add_misc(desc, inode, hmac_val);
 227        kfree(desc);
 228        return 0;
 229}
 230
 231/*
 232 * Get the key from the TPM for the SHA1-HMAC
 233 */
 234int evm_init_key(void)
 235{
 236        struct key *evm_key;
 237        struct encrypted_key_payload *ekp;
 238        int rc = 0;
 239
 240        evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
 241        if (IS_ERR(evm_key))
 242                return -ENOENT;
 243
 244        down_read(&evm_key->sem);
 245        ekp = evm_key->payload.data;
 246        if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
 247                rc = -EINVAL;
 248                goto out;
 249        }
 250        memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen);
 251out:
 252        /* burn the original key contents */
 253        memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
 254        up_read(&evm_key->sem);
 255        key_put(evm_key);
 256        return rc;
 257}
 258