linux/security/keys/permission.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Key permission checking
   3 *
   4 * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 */
   7
   8#include <linux/export.h>
   9#include <linux/security.h>
  10#include "internal.h"
  11
  12/**
  13 * key_task_permission - Check a key can be used
  14 * @key_ref: The key to check.
  15 * @cred: The credentials to use.
  16 * @need_perm: The permission required.
  17 *
  18 * Check to see whether permission is granted to use a key in the desired way,
  19 * but permit the security modules to override.
  20 *
  21 * The caller must hold either a ref on cred or must hold the RCU readlock.
  22 *
  23 * Returns 0 if successful, -EACCES if access is denied based on the
  24 * permissions bits or the LSM check.
  25 */
  26int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
  27                        enum key_need_perm need_perm)
  28{
  29        struct key *key;
  30        key_perm_t kperm, mask;
  31        int ret;
  32
  33        switch (need_perm) {
  34        default:
  35                WARN_ON(1);
  36                return -EACCES;
  37        case KEY_NEED_UNLINK:
  38        case KEY_SYSADMIN_OVERRIDE:
  39        case KEY_AUTHTOKEN_OVERRIDE:
  40        case KEY_DEFER_PERM_CHECK:
  41                goto lsm;
  42
  43        case KEY_NEED_VIEW:     mask = KEY_OTH_VIEW;    break;
  44        case KEY_NEED_READ:     mask = KEY_OTH_READ;    break;
  45        case KEY_NEED_WRITE:    mask = KEY_OTH_WRITE;   break;
  46        case KEY_NEED_SEARCH:   mask = KEY_OTH_SEARCH;  break;
  47        case KEY_NEED_LINK:     mask = KEY_OTH_LINK;    break;
  48        case KEY_NEED_SETATTR:  mask = KEY_OTH_SETATTR; break;
  49        }
  50
  51        key = key_ref_to_ptr(key_ref);
  52
  53        /* use the second 8-bits of permissions for keys the caller owns */
  54        if (uid_eq(key->uid, cred->fsuid)) {
  55                kperm = key->perm >> 16;
  56                goto use_these_perms;
  57        }
  58
  59        /* use the third 8-bits of permissions for keys the caller has a group
  60         * membership in common with */
  61        if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) {
  62                if (gid_eq(key->gid, cred->fsgid)) {
  63                        kperm = key->perm >> 8;
  64                        goto use_these_perms;
  65                }
  66
  67                ret = groups_search(cred->group_info, key->gid);
  68                if (ret) {
  69                        kperm = key->perm >> 8;
  70                        goto use_these_perms;
  71                }
  72        }
  73
  74        /* otherwise use the least-significant 8-bits */
  75        kperm = key->perm;
  76
  77use_these_perms:
  78
  79        /* use the top 8-bits of permissions for keys the caller possesses
  80         * - possessor permissions are additive with other permissions
  81         */
  82        if (is_key_possessed(key_ref))
  83                kperm |= key->perm >> 24;
  84
  85        if ((kperm & mask) != mask)
  86                return -EACCES;
  87
  88        /* let LSM be the final arbiter */
  89lsm:
  90        return security_key_permission(key_ref, cred, need_perm);
  91}
  92EXPORT_SYMBOL(key_task_permission);
  93
  94/**
  95 * key_validate - Validate a key.
  96 * @key: The key to be validated.
  97 *
  98 * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the
  99 * key is invalidated, -EKEYREVOKED if the key's type has been removed or if
 100 * the key has been revoked or -EKEYEXPIRED if the key has expired.
 101 */
 102int key_validate(const struct key *key)
 103{
 104        unsigned long flags = READ_ONCE(key->flags);
 105        time64_t expiry = READ_ONCE(key->expiry);
 106
 107        if (flags & (1 << KEY_FLAG_INVALIDATED))
 108                return -ENOKEY;
 109
 110        /* check it's still accessible */
 111        if (flags & ((1 << KEY_FLAG_REVOKED) |
 112                     (1 << KEY_FLAG_DEAD)))
 113                return -EKEYREVOKED;
 114
 115        /* check it hasn't expired */
 116        if (expiry) {
 117                if (ktime_get_real_seconds() >= expiry)
 118                        return -EKEYEXPIRED;
 119        }
 120
 121        return 0;
 122}
 123EXPORT_SYMBOL(key_validate);
 124