linux/security/keys/request_key.c
<<
>>
Prefs
   1/* request_key.c: request a key from userspace
   2 *
   3 * Copyright (C) 2004-6 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 License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 *
  11 * See Documentation/keys-request-key.txt
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/sched.h>
  16#include <linux/kmod.h>
  17#include <linux/err.h>
  18#include <linux/keyctl.h>
  19#include "internal.h"
  20
  21struct key_construction {
  22        struct list_head        link;   /* link in construction queue */
  23        struct key              *key;   /* key being constructed */
  24};
  25
  26/* when waiting for someone else's keys, you get added to this */
  27DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
  28
  29/*****************************************************************************/
  30/*
  31 * request userspace finish the construction of a key
  32 * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
  33 */
  34static int call_sbin_request_key(struct key *key,
  35                                 struct key *authkey,
  36                                 const char *op,
  37                                 void *aux)
  38{
  39        struct task_struct *tsk = current;
  40        key_serial_t prkey, sskey;
  41        struct key *keyring;
  42        char *argv[9], *envp[3], uid_str[12], gid_str[12];
  43        char key_str[12], keyring_str[3][12];
  44        char desc[20];
  45        int ret, i;
  46
  47        kenter("{%d},{%d},%s", key->serial, authkey->serial, op);
  48
  49        /* allocate a new session keyring */
  50        sprintf(desc, "_req.%u", key->serial);
  51
  52        keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
  53                                KEY_ALLOC_QUOTA_OVERRUN, NULL);
  54        if (IS_ERR(keyring)) {
  55                ret = PTR_ERR(keyring);
  56                goto error_alloc;
  57        }
  58
  59        /* attach the auth key to the session keyring */
  60        ret = __key_link(keyring, authkey);
  61        if (ret < 0)
  62                goto error_link;
  63
  64        /* record the UID and GID */
  65        sprintf(uid_str, "%d", current->fsuid);
  66        sprintf(gid_str, "%d", current->fsgid);
  67
  68        /* we say which key is under construction */
  69        sprintf(key_str, "%d", key->serial);
  70
  71        /* we specify the process's default keyrings */
  72        sprintf(keyring_str[0], "%d",
  73                tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
  74
  75        prkey = 0;
  76        if (tsk->signal->process_keyring)
  77                prkey = tsk->signal->process_keyring->serial;
  78
  79        sprintf(keyring_str[1], "%d", prkey);
  80
  81        if (tsk->signal->session_keyring) {
  82                rcu_read_lock();
  83                sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
  84                rcu_read_unlock();
  85        }
  86        else {
  87                sskey = tsk->user->session_keyring->serial;
  88        }
  89
  90        sprintf(keyring_str[2], "%d", sskey);
  91
  92        /* set up a minimal environment */
  93        i = 0;
  94        envp[i++] = "HOME=/";
  95        envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
  96        envp[i] = NULL;
  97
  98        /* set up the argument list */
  99        i = 0;
 100        argv[i++] = "/sbin/request-key";
 101        argv[i++] = (char *) op;
 102        argv[i++] = key_str;
 103        argv[i++] = uid_str;
 104        argv[i++] = gid_str;
 105        argv[i++] = keyring_str[0];
 106        argv[i++] = keyring_str[1];
 107        argv[i++] = keyring_str[2];
 108        argv[i] = NULL;
 109
 110        /* do it */
 111        ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1);
 112
 113error_link:
 114        key_put(keyring);
 115
 116error_alloc:
 117        kleave(" = %d", ret);
 118        return ret;
 119
 120} /* end call_sbin_request_key() */
 121
 122/*****************************************************************************/
 123/*
 124 * call out to userspace for the key
 125 * - called with the construction sem held, but the sem is dropped here
 126 * - we ignore program failure and go on key status instead
 127 */
 128static struct key *__request_key_construction(struct key_type *type,
 129                                              const char *description,
 130                                              const char *callout_info,
 131                                              void *aux,
 132                                              unsigned long flags)
 133{
 134        request_key_actor_t actor;
 135        struct key_construction cons;
 136        struct timespec now;
 137        struct key *key, *authkey;
 138        int ret, negated;
 139
 140        kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags);
 141
 142        /* create a key and add it to the queue */
 143        key = key_alloc(type, description,
 144                        current->fsuid, current->fsgid, current, KEY_POS_ALL,
 145                        flags);
 146        if (IS_ERR(key))
 147                goto alloc_failed;
 148
 149        set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
 150
 151        cons.key = key;
 152        list_add_tail(&cons.link, &key->user->consq);
 153
 154        /* we drop the construction sem here on behalf of the caller */
 155        up_write(&key_construction_sem);
 156
 157        /* allocate an authorisation key */
 158        authkey = request_key_auth_new(key, callout_info);
 159        if (IS_ERR(authkey)) {
 160                ret = PTR_ERR(authkey);
 161                authkey = NULL;
 162                goto alloc_authkey_failed;
 163        }
 164
 165        /* make the call */
 166        actor = call_sbin_request_key;
 167        if (type->request_key)
 168                actor = type->request_key;
 169        ret = actor(key, authkey, "create", aux);
 170        if (ret < 0)
 171                goto request_failed;
 172
 173        /* if the key wasn't instantiated, then we want to give an error */
 174        ret = -ENOKEY;
 175        if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
 176                goto request_failed;
 177
 178        key_revoke(authkey);
 179        key_put(authkey);
 180
 181        down_write(&key_construction_sem);
 182        list_del(&cons.link);
 183        up_write(&key_construction_sem);
 184
 185        /* also give an error if the key was negatively instantiated */
 186check_not_negative:
 187        if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
 188                key_put(key);
 189                key = ERR_PTR(-ENOKEY);
 190        }
 191
 192out:
 193        kleave(" = %p", key);
 194        return key;
 195
 196request_failed:
 197        key_revoke(authkey);
 198        key_put(authkey);
 199
 200alloc_authkey_failed:
 201        /* it wasn't instantiated
 202         * - remove from construction queue
 203         * - mark the key as dead
 204         */
 205        negated = 0;
 206        down_write(&key_construction_sem);
 207
 208        list_del(&cons.link);
 209
 210        /* check it didn't get instantiated between the check and the down */
 211        if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
 212                set_bit(KEY_FLAG_NEGATIVE, &key->flags);
 213                set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
 214                negated = 1;
 215        }
 216
 217        clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
 218
 219        up_write(&key_construction_sem);
 220
 221        if (!negated)
 222                goto check_not_negative; /* surprisingly, the key got
 223                                          * instantiated */
 224
 225        /* set the timeout and store in the session keyring if we can */
 226        now = current_kernel_time();
 227        key->expiry = now.tv_sec + key_negative_timeout;
 228
 229        if (current->signal->session_keyring) {
 230                struct key *keyring;
 231
 232                rcu_read_lock();
 233                keyring = rcu_dereference(current->signal->session_keyring);
 234                atomic_inc(&keyring->usage);
 235                rcu_read_unlock();
 236
 237                key_link(keyring, key);
 238                key_put(keyring);
 239        }
 240
 241        key_put(key);
 242
 243        /* notify anyone who was waiting */
 244        wake_up_all(&request_key_conswq);
 245
 246        key = ERR_PTR(ret);
 247        goto out;
 248
 249alloc_failed:
 250        up_write(&key_construction_sem);
 251        goto out;
 252
 253} /* end __request_key_construction() */
 254
 255/*****************************************************************************/
 256/*
 257 * call out to userspace to request the key
 258 * - we check the construction queue first to see if an appropriate key is
 259 *   already being constructed by userspace
 260 */
 261static struct key *request_key_construction(struct key_type *type,
 262                                            const char *description,
 263                                            const char *callout_info,
 264                                            void *aux,
 265                                            struct key_user *user,
 266                                            unsigned long flags)
 267{
 268        struct key_construction *pcons;
 269        struct key *key, *ckey;
 270
 271        DECLARE_WAITQUEUE(myself, current);
 272
 273        kenter("%s,%s,{%d},%s,%lx",
 274               type->name, description, user->uid, callout_info, flags);
 275
 276        /* see if there's such a key under construction already */
 277        down_write(&key_construction_sem);
 278
 279        list_for_each_entry(pcons, &user->consq, link) {
 280                ckey = pcons->key;
 281
 282                if (ckey->type != type)
 283                        continue;
 284
 285                if (type->match(ckey, description))
 286                        goto found_key_under_construction;
 287        }
 288
 289        /* see about getting userspace to construct the key */
 290        key = __request_key_construction(type, description, callout_info, aux,
 291                                         flags);
 292 error:
 293        kleave(" = %p", key);
 294        return key;
 295
 296        /* someone else has the same key under construction
 297         * - we want to keep an eye on their key
 298         */
 299 found_key_under_construction:
 300        atomic_inc(&ckey->usage);
 301        up_write(&key_construction_sem);
 302
 303        /* wait for the key to be completed one way or another */
 304        add_wait_queue(&request_key_conswq, &myself);
 305
 306        for (;;) {
 307                set_current_state(TASK_INTERRUPTIBLE);
 308                if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
 309                        break;
 310                if (signal_pending(current))
 311                        break;
 312                schedule();
 313        }
 314
 315        set_current_state(TASK_RUNNING);
 316        remove_wait_queue(&request_key_conswq, &myself);
 317
 318        /* we'll need to search this process's keyrings to see if the key is
 319         * now there since we can't automatically assume it's also available
 320         * there */
 321        key_put(ckey);
 322        ckey = NULL;
 323
 324        key = NULL; /* request a retry */
 325        goto error;
 326
 327} /* end request_key_construction() */
 328
 329/*****************************************************************************/
 330/*
 331 * link a freshly minted key to an appropriate destination keyring
 332 */
 333static void request_key_link(struct key *key, struct key *dest_keyring)
 334{
 335        struct task_struct *tsk = current;
 336        struct key *drop = NULL;
 337
 338        kenter("{%d},%p", key->serial, dest_keyring);
 339
 340        /* find the appropriate keyring */
 341        if (!dest_keyring) {
 342                switch (tsk->jit_keyring) {
 343                case KEY_REQKEY_DEFL_DEFAULT:
 344                case KEY_REQKEY_DEFL_THREAD_KEYRING:
 345                        dest_keyring = tsk->thread_keyring;
 346                        if (dest_keyring)
 347                                break;
 348
 349                case KEY_REQKEY_DEFL_PROCESS_KEYRING:
 350                        dest_keyring = tsk->signal->process_keyring;
 351                        if (dest_keyring)
 352                                break;
 353
 354                case KEY_REQKEY_DEFL_SESSION_KEYRING:
 355                        rcu_read_lock();
 356                        dest_keyring = key_get(
 357                                rcu_dereference(tsk->signal->session_keyring));
 358                        rcu_read_unlock();
 359                        drop = dest_keyring;
 360
 361                        if (dest_keyring)
 362                                break;
 363
 364                case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
 365                        dest_keyring = current->user->session_keyring;
 366                        break;
 367
 368                case KEY_REQKEY_DEFL_USER_KEYRING:
 369                        dest_keyring = current->user->uid_keyring;
 370                        break;
 371
 372                case KEY_REQKEY_DEFL_GROUP_KEYRING:
 373                default:
 374                        BUG();
 375                }
 376        }
 377
 378        /* and attach the key to it */
 379        key_link(dest_keyring, key);
 380
 381        key_put(drop);
 382
 383        kleave("");
 384
 385} /* end request_key_link() */
 386
 387/*****************************************************************************/
 388/*
 389 * request a key
 390 * - search the process's keyrings
 391 * - check the list of keys being created or updated
 392 * - call out to userspace for a key if supplementary info was provided
 393 * - cache the key in an appropriate keyring
 394 */
 395struct key *request_key_and_link(struct key_type *type,
 396                                 const char *description,
 397                                 const char *callout_info,
 398                                 void *aux,
 399                                 struct key *dest_keyring,
 400                                 unsigned long flags)
 401{
 402        struct key_user *user;
 403        struct key *key;
 404        key_ref_t key_ref;
 405
 406        kenter("%s,%s,%s,%p,%p,%lx",
 407               type->name, description, callout_info, aux,
 408               dest_keyring, flags);
 409
 410        /* search all the process keyrings for a key */
 411        key_ref = search_process_keyrings(type, description, type->match,
 412                                          current);
 413
 414        kdebug("search 1: %p", key_ref);
 415
 416        if (!IS_ERR(key_ref)) {
 417                key = key_ref_to_ptr(key_ref);
 418        }
 419        else if (PTR_ERR(key_ref) != -EAGAIN) {
 420                key = ERR_PTR(PTR_ERR(key_ref));
 421        }
 422        else  {
 423                /* the search failed, but the keyrings were searchable, so we
 424                 * should consult userspace if we can */
 425                key = ERR_PTR(-ENOKEY);
 426                if (!callout_info)
 427                        goto error;
 428
 429                /* - get hold of the user's construction queue */
 430                user = key_user_lookup(current->fsuid);
 431                if (!user)
 432                        goto nomem;
 433
 434                for (;;) {
 435                        if (signal_pending(current))
 436                                goto interrupted;
 437
 438                        /* ask userspace (returns NULL if it waited on a key
 439                         * being constructed) */
 440                        key = request_key_construction(type, description,
 441                                                       callout_info, aux,
 442                                                       user, flags);
 443                        if (key)
 444                                break;
 445
 446                        /* someone else made the key we want, so we need to
 447                         * search again as it might now be available to us */
 448                        key_ref = search_process_keyrings(type, description,
 449                                                          type->match,
 450                                                          current);
 451
 452                        kdebug("search 2: %p", key_ref);
 453
 454                        if (!IS_ERR(key_ref)) {
 455                                key = key_ref_to_ptr(key_ref);
 456                                break;
 457                        }
 458
 459                        if (PTR_ERR(key_ref) != -EAGAIN) {
 460                                key = ERR_PTR(PTR_ERR(key_ref));
 461                                break;
 462                        }
 463                }
 464
 465                key_user_put(user);
 466
 467                /* link the new key into the appropriate keyring */
 468                if (!IS_ERR(key))
 469                        request_key_link(key, dest_keyring);
 470        }
 471
 472error:
 473        kleave(" = %p", key);
 474        return key;
 475
 476nomem:
 477        key = ERR_PTR(-ENOMEM);
 478        goto error;
 479
 480interrupted:
 481        key_user_put(user);
 482        key = ERR_PTR(-EINTR);
 483        goto error;
 484
 485} /* end request_key_and_link() */
 486
 487/*****************************************************************************/
 488/*
 489 * request a key
 490 * - search the process's keyrings
 491 * - check the list of keys being created or updated
 492 * - call out to userspace for a key if supplementary info was provided
 493 */
 494struct key *request_key(struct key_type *type,
 495                        const char *description,
 496                        const char *callout_info)
 497{
 498        return request_key_and_link(type, description, callout_info, NULL,
 499                                    NULL, KEY_ALLOC_IN_QUOTA);
 500
 501} /* end request_key() */
 502
 503EXPORT_SYMBOL(request_key);
 504
 505/*****************************************************************************/
 506/*
 507 * request a key with auxiliary data for the upcaller
 508 * - search the process's keyrings
 509 * - check the list of keys being created or updated
 510 * - call out to userspace for a key if supplementary info was provided
 511 */
 512struct key *request_key_with_auxdata(struct key_type *type,
 513                                     const char *description,
 514                                     const char *callout_info,
 515                                     void *aux)
 516{
 517        return request_key_and_link(type, description, callout_info, aux,
 518                                    NULL, KEY_ALLOC_IN_QUOTA);
 519
 520} /* end request_key_with_auxdata() */
 521
 522EXPORT_SYMBOL(request_key_with_auxdata);
 523
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.