Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313// SPDX-License-Identifier: GPL-2.0-or-later/* Request key authorisation token key definition. * * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * See Documentation/security/keys/request-key.rst */
#include <linux/sched.h>#include <linux/err.h>#include <linux/seq_file.h>#include <linux/slab.h>#include <linux/uaccess.h>#include "internal.h"#include <keys/request_key_auth-type.h>
static int request_key_auth_preparse(struct key_preparsed_payload *);static void request_key_auth_free_preparse(struct key_preparsed_payload *);static int request_key_auth_instantiate(struct key *, struct key_preparsed_payload *);static void request_key_auth_describe(const struct key *, struct seq_file *);static void request_key_auth_revoke(struct key *);static void request_key_auth_destroy(struct key *);static long request_key_auth_read(const struct key *, char *, size_t);static void request_key_auth_rcu_disposal(struct rcu_head *);
/* * The request-key authorisation key type definition. */struct key_type key_type_request_key_auth = { .name = ".request_key_auth", .def_datalen = sizeof(struct request_key_auth), .preparse = request_key_auth_preparse, .free_preparse = request_key_auth_free_preparse, .instantiate = request_key_auth_instantiate, .describe = request_key_auth_describe, .revoke = request_key_auth_revoke, .destroy = request_key_auth_destroy, .read = request_key_auth_read,};
static int request_key_auth_preparse(struct key_preparsed_payload *prep){ return 0;}
static void request_key_auth_free_preparse(struct key_preparsed_payload *prep){}
/* * Instantiate a request-key authorisation key. */static int request_key_auth_instantiate(struct key *key, struct key_preparsed_payload *prep){ rcu_assign_keypointer(key, (struct request_key_auth *)prep->data); return 0;}
/* * Describe an authorisation token. */static void request_key_auth_describe(const struct key *key, struct seq_file *m){ struct request_key_auth *rka = dereference_key_rcu(key);
if (!rka) return;
seq_puts(m, "key:"); seq_puts(m, key->description); if (key_is_positive(key)) seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);}
/* * Read the callout_info data (retrieves the callout information). * - the key's semaphore is read-locked */static long request_key_auth_read(const struct key *key, char *buffer, size_t buflen){ struct request_key_auth *rka = dereference_key_locked(key); size_t datalen; long ret;
if (!rka) return -EKEYREVOKED;
datalen = rka->callout_len; ret = datalen;
/* we can return the data as is */ if (buffer && buflen > 0) { if (buflen > datalen) buflen = datalen;
memcpy(buffer, rka->callout_info, buflen); }
return ret;}
static void free_request_key_auth(struct request_key_auth *rka){ if (!rka) return; key_put(rka->target_key); key_put(rka->dest_keyring); if (rka->cred) put_cred(rka->cred); kfree(rka->callout_info); kfree(rka);}
/* * Take a reference to the request-key authorisation payload so callers can * drop authkey->sem before doing operations that may sleep. */struct request_key_auth *request_key_auth_get(struct key *authkey){ struct request_key_auth *rka;
down_read(&authkey->sem); rka = dereference_key_locked(authkey); if (rka && !test_bit(KEY_FLAG_REVOKED, &authkey->flags)) refcount_inc(&rka->usage); else rka = NULL; up_read(&authkey->sem);
return rka;}
void request_key_auth_put(struct request_key_auth *rka){ if (rka && refcount_dec_and_test(&rka->usage)) call_rcu(&rka->rcu, request_key_auth_rcu_disposal);}
/* * Dispose of the request_key_auth record under RCU conditions */static void request_key_auth_rcu_disposal(struct rcu_head *rcu){ struct request_key_auth *rka = container_of(rcu, struct request_key_auth, rcu);
free_request_key_auth(rka);}
/* * Handle revocation of an authorisation token key. * * Called with the key sem write-locked. */static void request_key_auth_revoke(struct key *key){ struct request_key_auth *rka = dereference_key_locked(key);
kenter("{%d}", key->serial); if (!rka) return; rcu_assign_keypointer(key, NULL); request_key_auth_put(rka);}
/* * Destroy an instantiation authorisation token key. */static void request_key_auth_destroy(struct key *key){ struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0);
kenter("{%d}", key->serial); if (rka) { rcu_assign_keypointer(key, NULL); request_key_auth_put(rka); }}
/* * Create an authorisation token for /sbin/request-key or whoever to gain * access to the caller's security data. */struct key *request_key_auth_new(struct key *target, const char *op, const void *callout_info, size_t callout_len, struct key *dest_keyring){ struct request_key_auth *rka, *irka; const struct cred *cred = current_cred(); struct key *authkey = NULL; char desc[20]; int ret = -ENOMEM;
kenter("%d,", target->serial);
/* allocate a auth record */ rka = kzalloc_obj(*rka); if (!rka) goto error; refcount_set(&rka->usage, 1); rka->callout_info = kmemdup(callout_info, callout_len, GFP_KERNEL); if (!rka->callout_info) goto error_free_rka; rka->callout_len = callout_len; strscpy(rka->op, op, sizeof(rka->op));
/* see if the calling process is already servicing the key request of * another process */ if (cred->request_key_auth) { /* it is - use that instantiation context here too */ down_read(&cred->request_key_auth->sem);
/* if the auth key has been revoked, then the key we're * servicing is already instantiated */ if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags)) { up_read(&cred->request_key_auth->sem); ret = -EKEYREVOKED; goto error_free_rka; }
irka = cred->request_key_auth->payload.data[0]; rka->cred = get_cred(irka->cred); rka->pid = irka->pid;
up_read(&cred->request_key_auth->sem); } else { /* it isn't - use this process as the context */ rka->cred = get_cred(cred); rka->pid = current->pid; }
rka->target_key = key_get(target); rka->dest_keyring = key_get(dest_keyring);
/* allocate the auth key */ sprintf(desc, "%x", target->serial);
authkey = key_alloc(&key_type_request_key_auth, desc, cred->fsuid, cred->fsgid, cred, KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_POS_LINK | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); if (IS_ERR(authkey)) { ret = PTR_ERR(authkey); goto error_free_rka; }
/* construct the auth key */ ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); if (ret < 0) goto error_put_authkey;
kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage)); return authkey;
error_put_authkey: key_put(authkey);error_free_rka: free_request_key_auth(rka);error: kleave("= %d", ret); return ERR_PTR(ret);}
/* * Search the current process's keyrings for the authorisation key for * instantiation of a key. */struct key *key_get_instantiation_authkey(key_serial_t target_id){ char description[16]; struct keyring_search_context ctx = { .index_key.type = &key_type_request_key_auth, .index_key.description = description, .cred = current_cred(), .match_data.cmp = key_default_cmp, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .flags = (KEYRING_SEARCH_DO_STATE_CHECK | KEYRING_SEARCH_RECURSE), }; struct key *authkey; key_ref_t authkey_ref;
ctx.index_key.desc_len = sprintf(description, "%x", target_id);
rcu_read_lock(); authkey_ref = search_process_keyrings_rcu(&ctx); rcu_read_unlock();
if (IS_ERR(authkey_ref)) { authkey = ERR_CAST(authkey_ref); if (authkey == ERR_PTR(-EAGAIN)) authkey = ERR_PTR(-ENOKEY); goto error; }
authkey = key_ref_to_ptr(authkey_ref); if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { key_put(authkey); authkey = ERR_PTR(-EKEYREVOKED); }
error: return authkey;}