linux/security/keys/big_key.c
<<
>>
Prefs
   1/* Large capacity key type
   2 *
   3 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#define pr_fmt(fmt) "big_key: "fmt
  13#include <linux/init.h>
  14#include <linux/seq_file.h>
  15#include <linux/file.h>
  16#include <linux/shmem_fs.h>
  17#include <linux/err.h>
  18#include <linux/scatterlist.h>
  19#include <keys/user-type.h>
  20#include <keys/big_key-type.h>
  21#include <crypto/rng.h>
  22#include <crypto/skcipher.h>
  23
  24/*
  25 * Layout of key payload words.
  26 */
  27enum {
  28        big_key_data,
  29        big_key_path,
  30        big_key_path_2nd_part,
  31        big_key_len,
  32};
  33
  34/*
  35 * Crypto operation with big_key data
  36 */
  37enum big_key_op {
  38        BIG_KEY_ENC,
  39        BIG_KEY_DEC,
  40};
  41
  42/*
  43 * If the data is under this limit, there's no point creating a shm file to
  44 * hold it as the permanently resident metadata for the shmem fs will be at
  45 * least as large as the data.
  46 */
  47#define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
  48
  49/*
  50 * Key size for big_key data encryption
  51 */
  52#define ENC_KEY_SIZE    16
  53
  54/*
  55 * big_key defined keys take an arbitrary string as the description and an
  56 * arbitrary blob of data as the payload
  57 */
  58struct key_type key_type_big_key = {
  59        .name                   = "big_key",
  60        .preparse               = big_key_preparse,
  61        .free_preparse          = big_key_free_preparse,
  62        .instantiate            = generic_key_instantiate,
  63        .revoke                 = big_key_revoke,
  64        .destroy                = big_key_destroy,
  65        .describe               = big_key_describe,
  66        .read                   = big_key_read,
  67};
  68
  69/*
  70 * Crypto names for big_key data encryption
  71 */
  72static const char big_key_rng_name[] = "stdrng";
  73static const char big_key_alg_name[] = "ecb(aes)";
  74
  75/*
  76 * Crypto algorithms for big_key data encryption
  77 */
  78static struct crypto_rng *big_key_rng;
  79static struct crypto_skcipher *big_key_skcipher;
  80
  81/*
  82 * Generate random key to encrypt big_key data
  83 */
  84static inline int big_key_gen_enckey(u8 *key)
  85{
  86        return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE);
  87}
  88
  89/*
  90 * Encrypt/decrypt big_key data
  91 */
  92static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
  93{
  94        int ret = -EINVAL;
  95        struct scatterlist sgio;
  96        SKCIPHER_REQUEST_ON_STACK(req, big_key_skcipher);
  97
  98        if (crypto_skcipher_setkey(big_key_skcipher, key, ENC_KEY_SIZE)) {
  99                ret = -EAGAIN;
 100                goto error;
 101        }
 102
 103        skcipher_request_set_tfm(req, big_key_skcipher);
 104        skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
 105                                      NULL, NULL);
 106
 107        sg_init_one(&sgio, data, datalen);
 108        skcipher_request_set_crypt(req, &sgio, &sgio, datalen, NULL);
 109
 110        if (op == BIG_KEY_ENC)
 111                ret = crypto_skcipher_encrypt(req);
 112        else
 113                ret = crypto_skcipher_decrypt(req);
 114
 115        skcipher_request_zero(req);
 116
 117error:
 118        return ret;
 119}
 120
 121/*
 122 * Preparse a big key
 123 */
 124int big_key_preparse(struct key_preparsed_payload *prep)
 125{
 126        struct path *path = (struct path *)&prep->payload.data[big_key_path];
 127        struct file *file;
 128        u8 *enckey;
 129        u8 *data = NULL;
 130        ssize_t written;
 131        size_t datalen = prep->datalen;
 132        int ret;
 133
 134        ret = -EINVAL;
 135        if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
 136                goto error;
 137
 138        /* Set an arbitrary quota */
 139        prep->quotalen = 16;
 140
 141        prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
 142
 143        if (datalen > BIG_KEY_FILE_THRESHOLD) {
 144                /* Create a shmem file to store the data in.  This will permit the data
 145                 * to be swapped out if needed.
 146                 *
 147                 * File content is stored encrypted with randomly generated key.
 148                 */
 149                size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher));
 150
 151                /* prepare aligned data to encrypt */
 152                data = kmalloc(enclen, GFP_KERNEL);
 153                if (!data)
 154                        return -ENOMEM;
 155
 156                memcpy(data, prep->data, datalen);
 157                memset(data + datalen, 0x00, enclen - datalen);
 158
 159                /* generate random key */
 160                enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
 161                if (!enckey) {
 162                        ret = -ENOMEM;
 163                        goto error;
 164                }
 165
 166                ret = big_key_gen_enckey(enckey);
 167                if (ret)
 168                        goto err_enckey;
 169
 170                /* encrypt aligned data */
 171                ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey);
 172                if (ret)
 173                        goto err_enckey;
 174
 175                /* save aligned data to file */
 176                file = shmem_kernel_file_setup("", enclen, 0);
 177                if (IS_ERR(file)) {
 178                        ret = PTR_ERR(file);
 179                        goto err_enckey;
 180                }
 181
 182                written = kernel_write(file, data, enclen, 0);
 183                if (written != enclen) {
 184                        ret = written;
 185                        if (written >= 0)
 186                                ret = -ENOMEM;
 187                        goto err_fput;
 188                }
 189
 190                /* Pin the mount and dentry to the key so that we can open it again
 191                 * later
 192                 */
 193                prep->payload.data[big_key_data] = enckey;
 194                *path = file->f_path;
 195                path_get(path);
 196                fput(file);
 197                kfree(data);
 198        } else {
 199                /* Just store the data in a buffer */
 200                void *data = kmalloc(datalen, GFP_KERNEL);
 201
 202                if (!data)
 203                        return -ENOMEM;
 204
 205                prep->payload.data[big_key_data] = data;
 206                memcpy(data, prep->data, prep->datalen);
 207        }
 208        return 0;
 209
 210err_fput:
 211        fput(file);
 212err_enckey:
 213        kfree(enckey);
 214error:
 215        kfree(data);
 216        return ret;
 217}
 218
 219/*
 220 * Clear preparsement.
 221 */
 222void big_key_free_preparse(struct key_preparsed_payload *prep)
 223{
 224        if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
 225                struct path *path = (struct path *)&prep->payload.data[big_key_path];
 226
 227                path_put(path);
 228        }
 229        kfree(prep->payload.data[big_key_data]);
 230}
 231
 232/*
 233 * dispose of the links from a revoked keyring
 234 * - called with the key sem write-locked
 235 */
 236void big_key_revoke(struct key *key)
 237{
 238        struct path *path = (struct path *)&key->payload.data[big_key_path];
 239
 240        /* clear the quota */
 241        key_payload_reserve(key, 0);
 242        if (key_is_instantiated(key) &&
 243            (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
 244                vfs_truncate(path, 0);
 245}
 246
 247/*
 248 * dispose of the data dangling from the corpse of a big_key key
 249 */
 250void big_key_destroy(struct key *key)
 251{
 252        size_t datalen = (size_t)key->payload.data[big_key_len];
 253
 254        if (datalen > BIG_KEY_FILE_THRESHOLD) {
 255                struct path *path = (struct path *)&key->payload.data[big_key_path];
 256
 257                path_put(path);
 258                path->mnt = NULL;
 259                path->dentry = NULL;
 260        }
 261        kfree(key->payload.data[big_key_data]);
 262        key->payload.data[big_key_data] = NULL;
 263}
 264
 265/*
 266 * describe the big_key key
 267 */
 268void big_key_describe(const struct key *key, struct seq_file *m)
 269{
 270        size_t datalen = (size_t)key->payload.data[big_key_len];
 271
 272        seq_puts(m, key->description);
 273
 274        if (key_is_instantiated(key))
 275                seq_printf(m, ": %zu [%s]",
 276                           datalen,
 277                           datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
 278}
 279
 280/*
 281 * read the key data
 282 * - the key's semaphore is read-locked
 283 */
 284long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
 285{
 286        size_t datalen = (size_t)key->payload.data[big_key_len];
 287        long ret;
 288
 289        if (!buffer || buflen < datalen)
 290                return datalen;
 291
 292        if (datalen > BIG_KEY_FILE_THRESHOLD) {
 293                struct path *path = (struct path *)&key->payload.data[big_key_path];
 294                struct file *file;
 295                u8 *data;
 296                u8 *enckey = (u8 *)key->payload.data[big_key_data];
 297                size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher));
 298
 299                data = kmalloc(enclen, GFP_KERNEL);
 300                if (!data)
 301                        return -ENOMEM;
 302
 303                file = dentry_open(path, O_RDONLY, current_cred());
 304                if (IS_ERR(file)) {
 305                        ret = PTR_ERR(file);
 306                        goto error;
 307                }
 308
 309                /* read file to kernel and decrypt */
 310                ret = kernel_read(file, 0, data, enclen);
 311                if (ret >= 0 && ret != enclen) {
 312                        ret = -EIO;
 313                        goto err_fput;
 314                }
 315
 316                ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
 317                if (ret)
 318                        goto err_fput;
 319
 320                ret = datalen;
 321
 322                /* copy decrypted data to user */
 323                if (copy_to_user(buffer, data, datalen) != 0)
 324                        ret = -EFAULT;
 325
 326err_fput:
 327                fput(file);
 328error:
 329                kfree(data);
 330        } else {
 331                ret = datalen;
 332                if (copy_to_user(buffer, key->payload.data[big_key_data],
 333                                 datalen) != 0)
 334                        ret = -EFAULT;
 335        }
 336
 337        return ret;
 338}
 339
 340/*
 341 * Register key type
 342 */
 343static int __init big_key_init(void)
 344{
 345        struct crypto_skcipher *cipher;
 346        struct crypto_rng *rng;
 347        int ret;
 348
 349        rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
 350        if (IS_ERR(rng)) {
 351                pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng));
 352                return PTR_ERR(rng);
 353        }
 354
 355        big_key_rng = rng;
 356
 357        /* seed RNG */
 358        ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
 359        if (ret) {
 360                pr_err("Can't reset rng: %d\n", ret);
 361                goto error_rng;
 362        }
 363
 364        /* init block cipher */
 365        cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
 366        if (IS_ERR(cipher)) {
 367                ret = PTR_ERR(cipher);
 368                pr_err("Can't alloc crypto: %d\n", ret);
 369                goto error_rng;
 370        }
 371
 372        big_key_skcipher = cipher;
 373
 374        ret = register_key_type(&key_type_big_key);
 375        if (ret < 0) {
 376                pr_err("Can't register type: %d\n", ret);
 377                goto error_cipher;
 378        }
 379
 380        return 0;
 381
 382error_cipher:
 383        crypto_free_skcipher(big_key_skcipher);
 384error_rng:
 385        crypto_free_rng(big_key_rng);
 386        return ret;
 387}
 388
 389late_initcall(big_key_init);
 390