/* * RSAVP1() function [RFC3447 sec 5.2.2] */ static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) { MPI m; int ret; /* (1) Validate 0 <= s < n */ if (mpi_cmp_ui(s, 0) < 0) { kleave(" = -EBADMSG [s < 0]"); return -EBADMSG; } if (mpi_cmp(s, key->rsa.n) >= 0) { kleave(" = -EBADMSG [s >= n]"); return -EBADMSG; } m = mpi_alloc(0); if (!m) return -ENOMEM; /* (2) m = s^e mod n */ ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); if (ret < 0) { mpi_free(m); return ret; } *_m = m; return 0; }
/* * allocate a new key in under-construction state and attempt to link it in to * the requested place * - may return a key that's already under construction instead */ static int construct_alloc_key(struct key_type *type, const char *description, struct key *dest_keyring, unsigned long flags, struct key_user *user, struct key **_key) { const struct cred *cred = current_cred(); struct key *key; key_ref_t key_ref; kenter("%s,%s,,,", type->name, description); mutex_lock(&user->cons_lock); key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, KEY_POS_ALL, flags); if (IS_ERR(key)) goto alloc_failed; set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); down_write(&dest_keyring->sem); /* attach the key to the destination keyring under lock, but we do need * to do another check just in case someone beat us to it whilst we * waited for locks */ mutex_lock(&key_construction_mutex); key_ref = search_process_keyrings(type, description, type->match, cred); if (!IS_ERR(key_ref)) goto key_already_present; __key_link(dest_keyring, key); mutex_unlock(&key_construction_mutex); up_write(&dest_keyring->sem); mutex_unlock(&user->cons_lock); *_key = key; kleave(" = 0 [%d]", key_serial(key)); return 0; key_already_present: mutex_unlock(&key_construction_mutex); if (dest_keyring) up_write(&dest_keyring->sem); mutex_unlock(&user->cons_lock); key_put(key); *_key = key = key_ref_to_ptr(key_ref); kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS; alloc_failed: mutex_unlock(&user->cons_lock); *_key = NULL; kleave(" = %ld", PTR_ERR(key)); return PTR_ERR(key); }
/* * Commence key construction. */ static struct key *construct_key_and_link(struct keyring_search_context *ctx, const char *callout_info, size_t callout_len, void *aux, struct key *dest_keyring, unsigned long flags) { struct key_user *user; struct key *key; int ret; kenter(""); if (ctx->index_key.type == &key_type_keyring) return ERR_PTR(-EPERM); user = key_user_lookup(current_fsuid()); if (!user) return ERR_PTR(-ENOMEM); construct_get_dest_keyring(&dest_keyring); ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); key_user_put(user); if (ret == 0) { ret = construct_key(key, callout_info, callout_len, aux, dest_keyring); if (ret < 0) { kdebug("cons failed"); goto construction_failed; } } else if (ret == -EINPROGRESS) { ret = 0; } else { goto couldnt_alloc_key; } key_put(dest_keyring); kleave(" = key %d", key_serial(key)); return key; construction_failed: key_negate_and_link(key, key_negative_timeout, NULL, NULL); key_put(key); couldnt_alloc_key: key_put(dest_keyring); kleave(" = %d", ret); return ERR_PTR(ret); }
/* * Perform the verification step [RFC3447 sec 8.2.2]. */ static int RSA_verify_signature(const struct public_key *key, const struct public_key_signature *sig) { size_t tsize; int ret; /* Variables as per RFC3447 sec 8.2.2 */ const u8 *H = sig->digest; u8 *EM = NULL; MPI m = NULL; size_t k; kenter(""); if (!RSA_ASN1_templates[sig->pkey_hash_algo].data) return -ENOTSUPP; /* (1) Check the signature size against the public key modulus size */ k = mpi_get_nbits(key->rsa.n); tsize = mpi_get_nbits(sig->rsa.s); /* According to RFC 4880 sec 3.2, length of MPI is computed starting * from most significant bit. So the RFC 3447 sec 8.2.2 size check * must be relaxed to conform with shorter signatures - so we fail here * only if signature length is longer than modulus size. */ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); if (k < tsize) { ret = -EBADMSG; goto error; } /* Round up and convert to octets */ k = (k + 7) / 8; /* (2b) Apply the RSAVP1 verification primitive to the public key */ ret = RSAVP1(key, sig->rsa.s, &m); if (ret < 0) goto error; /* (2c) Convert the message representative (m) to an encoded message * (EM) of length k octets. * * NOTE! The leading zero byte is suppressed by MPI, so we pass a * pointer to the _preceding_ byte to RSA_verify()! */ ret = RSA_I2OSP(m, k, &EM); if (ret < 0) goto error; ret = RSA_verify(H, EM - 1, k, sig->digest_size, RSA_ASN1_templates[sig->pkey_hash_algo].data, RSA_ASN1_templates[sig->pkey_hash_algo].size); error: kfree(EM); mpi_free(m); kleave(" = %d", ret); return ret; }
/* * connection-level Rx packet processor */ static int rxrpc_process_event(struct rxrpc_connection *conn, struct sk_buff *skb, u32 *_abort_code) { struct rxrpc_skb_priv *sp = rxrpc_skb(skb); __be32 wtmp; u32 abort_code; int loop, ret; if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) { kleave(" = -ECONNABORTED [%u]", conn->state); return -ECONNABORTED; } _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial); switch (sp->hdr.type) { case RXRPC_PACKET_TYPE_ABORT: if (skb_copy_bits(skb, 0, &wtmp, sizeof(wtmp)) < 0) return -EPROTO; abort_code = ntohl(wtmp); _proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code); conn->state = RXRPC_CONN_REMOTELY_ABORTED; rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, abort_code); return -ECONNABORTED; case RXRPC_PACKET_TYPE_CHALLENGE: return conn->security->respond_to_challenge(conn, skb, _abort_code); case RXRPC_PACKET_TYPE_RESPONSE: ret = conn->security->verify_response(conn, skb, _abort_code); if (ret < 0) return ret; ret = conn->security->init_connection_security(conn); if (ret < 0) return ret; conn->security->prime_packet_security(conn); read_lock_bh(&conn->lock); spin_lock(&conn->state_lock); if (conn->state == RXRPC_CONN_SERVER_CHALLENGING) { conn->state = RXRPC_CONN_SERVER; for (loop = 0; loop < RXRPC_MAXCALLS; loop++) rxrpc_call_is_secure(conn->channels[loop]); } spin_unlock(&conn->state_lock); read_unlock_bh(&conn->lock); return 0; default: _leave(" = -EPROTO [%u]", sp->hdr.type); return -EPROTO; } }
/* * commence key construction */ static struct key *construct_key_and_link(struct key_type *type, const char *description, const char *callout_info, size_t callout_len, void *aux, struct key *dest_keyring, unsigned long flags) { struct key_user *user; struct key *key; int ret; kenter(""); user = key_user_lookup(current_fsuid(), current_user_ns()); if (!user) return ERR_PTR(-ENOMEM); construct_get_dest_keyring(&dest_keyring); ret = construct_alloc_key(type, description, dest_keyring, flags, user, &key); key_user_put(user); if (ret == 0) { ret = construct_key(key, callout_info, callout_len, aux, dest_keyring); if (ret < 0) { kdebug("cons failed"); goto construction_failed; } } key_put(dest_keyring); kleave(" = key %d", key_serial(key)); return key; construction_failed: key_negate_and_link(key, key_negative_timeout, NULL, NULL); key_put(key); key_put(dest_keyring); kleave(" = %d", ret); return ERR_PTR(ret); }
/* * create a session keyring to be for the invokation of /sbin/request-key and * stick an authorisation token in it */ struct key *request_key_auth_new(struct key *target, struct key **_rkakey) { struct key *keyring, *rkakey = NULL; char desc[20]; int ret; kenter("%d,", target->serial); /* allocate a new session keyring */ sprintf(desc, "_req.%u", target->serial); keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); if (IS_ERR(keyring)) { kleave("= %ld", PTR_ERR(keyring)); return keyring; } /* allocate the auth key */ sprintf(desc, "%x", target->serial); rkakey = key_alloc(&key_type_request_key_auth, desc, current->fsuid, current->fsgid, KEY_USR_VIEW, 1); if (IS_ERR(rkakey)) { key_put(keyring); kleave("= %ld", PTR_ERR(rkakey)); return rkakey; } /* construct and attach to the keyring */ ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL); if (ret < 0) { key_revoke(rkakey); key_put(rkakey); key_put(keyring); kleave("= %d", ret); return ERR_PTR(ret); } *_rkakey = rkakey; kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial); return keyring; } /* end request_key_auth_new() */
/* * handle mountpoint expiry timer going off */ static void afs_mntpt_expiry_timed_out(struct afs_timer *timer) { kenter(""); mark_mounts_for_expiry(&afs_vfsmounts); afs_kafstimod_add_timer(&afs_mntpt_expiry_timer, afs_mntpt_expiry_timeout * HZ); kleave(""); } /* end afs_mntpt_expiry_timed_out() */
/* * Garbage collect pointers from a keyring. * * Not called with any locks held. The keyring's key struct will not be * deallocated under us as only our caller may deallocate it. */ static void key_gc_keyring(struct key *keyring, time_t limit) { struct keyring_list *klist; struct key *key; int loop; kenter("%x", key_serial(keyring)); if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) goto dont_gc; /* scan the keyring looking for dead keys */ rcu_read_lock(); klist = rcu_dereference(keyring->payload.subscriptions); if (!klist) goto unlock_dont_gc; loop = klist->nkeys; smp_rmb(); for (loop--; loop >= 0; loop--) { key = klist->keys[loop]; if (test_bit(KEY_FLAG_DEAD, &key->flags) || (key->expiry > 0 && key->expiry <= limit)) goto do_gc; } unlock_dont_gc: rcu_read_unlock(); dont_gc: kleave(" [no gc]"); return; do_gc: rcu_read_unlock(); keyring_gc(keyring, limit); kleave(" [gc]"); }
/* * link a key to the appropriate destination keyring * - the caller must hold a write lock on the destination keyring */ static void construct_key_make_link(struct key *key, struct key *dest_keyring) { struct task_struct *tsk = current; struct key *drop = NULL; kenter("{%d},%p", key->serial, dest_keyring); /* find the appropriate keyring */ if (!dest_keyring) { switch (tsk->jit_keyring) { case KEY_REQKEY_DEFL_DEFAULT: case KEY_REQKEY_DEFL_THREAD_KEYRING: dest_keyring = tsk->thread_keyring; if (dest_keyring) break; case KEY_REQKEY_DEFL_PROCESS_KEYRING: dest_keyring = tsk->signal->process_keyring; if (dest_keyring) break; case KEY_REQKEY_DEFL_SESSION_KEYRING: rcu_read_lock(); dest_keyring = key_get( rcu_dereference(tsk->signal->session_keyring)); rcu_read_unlock(); drop = dest_keyring; if (dest_keyring) break; case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: dest_keyring = tsk->user->session_keyring; break; case KEY_REQKEY_DEFL_USER_KEYRING: dest_keyring = tsk->user->uid_keyring; break; case KEY_REQKEY_DEFL_GROUP_KEYRING: default: BUG(); } } /* and attach the key to it */ __key_link(dest_keyring, key); key_put(drop); kleave(""); }
/** * request_key_and_link - Request a key and cache it in a keyring. * @type: The type of key we want. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * @dest_keyring: Where to cache the key. * @flags: Flags to key_alloc(). * * A key matching the specified criteria is searched for in the process's * keyrings and returned with its usage count incremented if found. Otherwise, * if callout_info is not NULL, a key will be allocated and some service * (probably in userspace) will be asked to instantiate it. * * If successfully found or created, the key will be linked to the destination * keyring if one is provided. * * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT * if insufficient key quota was available to create a new key; or -ENOMEM if * insufficient memory was available. * * If the returned key was created, then it may still be under construction, * and wait_for_key_construction() should be used to wait for that to complete. */ struct key *request_key_and_link(struct key_type *type, const char *description, const void *callout_info, size_t callout_len, void *aux, struct key *dest_keyring, unsigned long flags) { const struct cred *cred = current_cred(); struct key *key; key_ref_t key_ref; int ret; kenter("%s,%s,%p,%zu,%p,%p,%lx", type->name, description, callout_info, callout_len, aux, dest_keyring, flags); /* search all the process keyrings for a key */ key_ref = search_process_keyrings(type, description, type->match, cred); if (!IS_ERR(key_ref)) { key = key_ref_to_ptr(key_ref); if (dest_keyring) { construct_get_dest_keyring(&dest_keyring); ret = key_link(dest_keyring, key); key_put(dest_keyring); if (ret < 0) { key_put(key); key = ERR_PTR(ret); goto error; } } } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_CAST(key_ref); } else { /* the search failed, but the keyrings were searchable, so we * should consult userspace if we can */ key = ERR_PTR(-ENOKEY); if (!callout_info) goto error; key = construct_key_and_link(type, description, callout_info, callout_len, aux, dest_keyring, flags); } error: kleave(" = %p", key); return key; }
/* * Garbage collect pointers from a keyring. * * Not called with any locks held. The keyring's key struct will not be * deallocated under us as only our caller may deallocate it. */ static void key_gc_keyring(struct key *keyring, time_t limit) { struct keyring_list *klist; int loop; kenter("%x", key_serial(keyring)); if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED))) goto dont_gc; /* scan the keyring looking for dead keys */ rcu_read_lock(); klist = rcu_dereference(keyring->payload.subscriptions); if (!klist) goto unlock_dont_gc; loop = klist->nkeys; smp_rmb(); for (loop--; loop >= 0; loop--) { struct key *key = rcu_dereference(klist->keys[loop]); if (key_is_dead(key, limit)) goto do_gc; } unlock_dont_gc: rcu_read_unlock(); dont_gc: kleave(" [no gc]"); return; do_gc: rcu_read_unlock(); keyring_gc(keyring, limit); kleave(" [gc]"); }
/* * Instantiate a PKCS#7 wrapped and validated key. */ int pkcs7_instantiate(struct key *key, struct key_preparsed_payload *prep) { struct pkcs7_message *pkcs7; const void *data, *saved_prep_data; size_t datalen, saved_prep_datalen; bool trusted; int ret; kenter(""); saved_prep_data = prep->data; saved_prep_datalen = prep->datalen; pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); if (IS_ERR(pkcs7)) { ret = PTR_ERR(pkcs7); goto error; } ret = pkcs7_verify(pkcs7); if (ret < 0) goto error_free; ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); if (ret < 0) goto error_free; if (!trusted) pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); if (ret < 0) goto error_free; prep->data = data; prep->datalen = datalen; ret = user_instantiate(key, prep); prep->data = saved_prep_data; prep->datalen = saved_prep_datalen; error_free: pkcs7_free_message(pkcs7); error: kleave(" = %d", ret); return ret; }
/* * Call out to userspace for key construction. * * Program failure is ignored in favour of key status. */ static int construct_key(struct key *key, const void *callout_info, size_t callout_len, void *aux, struct key *dest_keyring) { struct key_construction *cons; request_key_actor_t actor; struct key *authkey; int ret; kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux); cons = kmalloc(sizeof(*cons), GFP_KERNEL); if (!cons) return -ENOMEM; /* allocate an authorisation key */ authkey = request_key_auth_new(key, callout_info, callout_len, dest_keyring); if (IS_ERR(authkey)) { kfree(cons); ret = PTR_ERR(authkey); authkey = NULL; } else { cons->authkey = key_get(authkey); cons->key = key_get(key); /* make the call */ actor = call_sbin_request_key; if (key->type->request_key) actor = key->type->request_key; ret = actor(cons, "create", aux); /* check that the actor called complete_request_key() prior to * returning an error */ WARN_ON(ret < 0 && !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); key_put(authkey); } kleave(" = %d", ret); return ret; }
/* * Reap keys of dead type. * * We use three flags to make sure we see three complete cycles of the garbage * collector: the first to mark keys of that type as being dead, the second to * collect dead links and the third to clean up the dead keys. We have to be * careful as there may already be a cycle in progress. * * The caller must be holding key_types_sem. */ void key_gc_keytype(struct key_type *ktype) { kenter("%s", ktype->name); key_gc_dead_keytype = ktype; set_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); smp_mb(); set_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags); kdebug("schedule"); schedule_work(&key_gc_work); kdebug("sleep"); wait_on_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE, key_gc_wait_bit, TASK_UNINTERRUPTIBLE); key_gc_dead_keytype = NULL; kleave(""); }
/* * request a key * - search the process's keyrings * - check the list of keys being created or updated * - call out to userspace for a key if supplementary info was provided * - cache the key in an appropriate keyring */ struct key *request_key_and_link(struct key_type *type, const char *description, const char *callout_info, void *aux, struct key *dest_keyring, unsigned long flags) { struct key *key; key_ref_t key_ref; kenter("%s,%s,%s,%p,%p,%lx", type->name, description, callout_info, aux, dest_keyring, flags); /* search all the process keyrings for a key */ key_ref = search_process_keyrings(type, description, type->match, current); if (!IS_ERR(key_ref)) { key = key_ref_to_ptr(key_ref); } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_PTR(PTR_ERR(key_ref)); } else { /* the search failed, but the keyrings were searchable, so we * should consult userspace if we can */ key = ERR_PTR(-ENOKEY); if (!callout_info) goto error; key = construct_key_and_link(type, description, callout_info, aux, dest_keyring, flags); } error: kleave(" = %p", key); return key; }
/* * follow a link from a mountpoint directory, thus causing it to be mounted */ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *newmnt; struct dentry *old_dentry; int err; kenter("%p{%s},{%s:%p{%s}}", dentry, dentry->d_name.name, nd->mnt->mnt_devname, dentry, nd->dentry->d_name.name); newmnt = afs_mntpt_do_automount(dentry); if (IS_ERR(newmnt)) { path_release(nd); return (void *)newmnt; } old_dentry = nd->dentry; nd->dentry = dentry; err = do_add_mount(newmnt, nd, 0, &afs_vfsmounts); nd->dentry = old_dentry; path_release(nd); if (!err) { mntget(newmnt); nd->mnt = newmnt; dget(newmnt->mnt_root); nd->dentry = newmnt->mnt_root; } kleave(" = %d", err); return ERR_PTR(err); } /* end afs_mntpt_follow_link() */
/* * Perform the RSA signature verification. * @H: Value of hash of data and metadata * @EM: The computed signature value * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) * @hash_size: The size of H * @asn1_template: The DigestInfo ASN.1 template * @asn1_size: Size of asm1_template[] */ static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, const u8 *asn1_template, size_t asn1_size) { unsigned PS_end, T_offset, i; kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); if (k < 2 + 1 + asn1_size + hash_size) return -EBADMSG; /* Decode the EMSA-PKCS1-v1_5 */ if (EM[1] != 0x01) { kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); return -EBADMSG; } T_offset = k - (asn1_size + hash_size); PS_end = T_offset - 1; if (EM[PS_end] != 0x00) { kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); return -EBADMSG; } for (i = 2; i < PS_end; i++) { if (EM[i] != 0xff) { kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); return -EBADMSG; } } if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) { kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); return -EBADMSG; } if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) { kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); return -EKEYREJECTED; } kleave(" = 0"); return 0; }
/* * Allocate a new key in under-construction state and attempt to link it in to * the requested keyring. * * May return a key that's already under construction instead if there was a * race between two thread calling request_key(). */ static int construct_alloc_key(struct key_type *type, const char *description, struct key *dest_keyring, unsigned long flags, struct key_user *user, struct key **_key) { const struct cred *cred = current_cred(); unsigned long prealloc; struct key *key; key_ref_t key_ref; int ret; kenter("%s,%s,,,", type->name, description); *_key = NULL; mutex_lock(&user->cons_lock); key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, KEY_POS_ALL, flags); if (IS_ERR(key)) goto alloc_failed; set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); if (dest_keyring) { ret = __key_link_begin(dest_keyring, type, description, &prealloc); if (ret < 0) goto link_prealloc_failed; } /* attach the key to the destination keyring under lock, but we do need * to do another check just in case someone beat us to it whilst we * waited for locks */ mutex_lock(&key_construction_mutex); key_ref = search_process_keyrings(type, description, type->match, cred); if (!IS_ERR(key_ref)) goto key_already_present; if (dest_keyring) __key_link(dest_keyring, key, &prealloc); mutex_unlock(&key_construction_mutex); if (dest_keyring) __key_link_end(dest_keyring, type, prealloc); mutex_unlock(&user->cons_lock); *_key = key; kleave(" = 0 [%d]", key_serial(key)); return 0; /* the key is now present - we tell the caller that we found it by * returning -EINPROGRESS */ key_already_present: key_put(key); mutex_unlock(&key_construction_mutex); key = key_ref_to_ptr(key_ref); if (dest_keyring) { ret = __key_link_check_live_key(dest_keyring, key); if (ret == 0) __key_link(dest_keyring, key, &prealloc); __key_link_end(dest_keyring, type, prealloc); if (ret < 0) goto link_check_failed; } mutex_unlock(&user->cons_lock); *_key = key; kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS; link_check_failed: mutex_unlock(&user->cons_lock); key_put(key); kleave(" = %d [linkcheck]", ret); return ret; link_prealloc_failed: mutex_unlock(&user->cons_lock); kleave(" = %d [prelink]", ret); return ret; alloc_failed: mutex_unlock(&user->cons_lock); kleave(" = %ld", PTR_ERR(key)); return PTR_ERR(key); }
/** * dns_query - Query the DNS * @type: Query type (or NULL for straight host->IP lookup) * @name: Name to look up * @namelen: Length of name * @options: Request options (or NULL if no options) * @_result: Where to place the returned data (or NULL) * @_expiry: Where to store the result expiry time (or NULL) * * The data will be returned in the pointer at *result, if provided, and the * caller is responsible for freeing it. * * The description should be of the form "[<query_type>:]<domain_name>", and * the options need to be appropriate for the query type requested. If no * query_type is given, then the query is a straight hostname to IP address * lookup. * * The DNS resolution lookup is performed by upcalling to userspace by way of * requesting a key of type dns_resolver. * * Returns the size of the result on success, -ve error code otherwise. */ int dns_query(const char *type, const char *name, size_t namelen, const char *options, char **_result, time64_t *_expiry) { struct key *rkey; struct user_key_payload *upayload; const struct cred *saved_cred; size_t typelen, desclen; char *desc, *cp; int ret, len; kenter("%s,%*.*s,%zu,%s", type, (int)namelen, (int)namelen, name, namelen, options); if (!name || namelen == 0) return -EINVAL; /* construct the query key description as "[<type>:]<name>" */ typelen = 0; desclen = 0; if (type) { typelen = strlen(type); if (typelen < 1) return -EINVAL; desclen += typelen + 1; } if (!namelen) namelen = strnlen(name, 256); if (namelen < 3 || namelen > 255) return -EINVAL; desclen += namelen + 1; desc = kmalloc(desclen, GFP_KERNEL); if (!desc) return -ENOMEM; cp = desc; if (type) { memcpy(cp, type, typelen); cp += typelen; *cp++ = ':'; } memcpy(cp, name, namelen); cp += namelen; *cp = '\0'; if (!options) options = ""; kdebug("call request_key(,%s,%s)", desc, options); /* make the upcall, using special credentials to prevent the use of * add_key() to preinstall malicious redirections */ saved_cred = override_creds(dns_resolver_cache); rkey = request_key(&key_type_dns_resolver, desc, options); revert_creds(saved_cred); kfree(desc); if (IS_ERR(rkey)) { ret = PTR_ERR(rkey); goto out; } down_read(&rkey->sem); set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); rkey->perm |= KEY_USR_VIEW; ret = key_validate(rkey); if (ret < 0) goto put; /* If the DNS server gave an error, return that to the caller */ ret = PTR_ERR(rkey->payload.data[dns_key_error]); if (ret) goto put; upayload = user_key_payload_locked(rkey); len = upayload->datalen; if (_result) { ret = -ENOMEM; *_result = kmalloc(len + 1, GFP_KERNEL); if (!*_result) goto put; memcpy(*_result, upayload->data, len); (*_result)[len] = '\0'; } if (_expiry) *_expiry = rkey->expiry; ret = len; put: up_read(&rkey->sem); key_put(rkey); out: kleave(" = %d", ret); return ret; }
static void key_garbage_collector(struct work_struct *work) { struct rb_node *rb; key_serial_t cursor; struct key *key, *xkey; time_t new_timer = LONG_MAX, limit, now; now = current_kernel_time().tv_sec; kenter("[%x,%ld]", key_gc_cursor, key_gc_new_timer - now); if (test_and_set_bit(0, &key_gc_executing)) { key_schedule_gc(current_kernel_time().tv_sec + 1); kleave(" [busy; deferring]"); return; } limit = now; if (limit > key_gc_delay) limit -= key_gc_delay; else limit = key_gc_delay; spin_lock(&key_serial_lock); if (unlikely(RB_EMPTY_ROOT(&key_serial_tree))) { spin_unlock(&key_serial_lock); clear_bit(0, &key_gc_executing); return; } cursor = key_gc_cursor; if (cursor < 0) cursor = 0; if (cursor > 0) new_timer = key_gc_new_timer; else key_gc_again = false; /* find the first key above the cursor */ key = NULL; rb = key_serial_tree.rb_node; while (rb) { xkey = rb_entry(rb, struct key, serial_node); if (cursor < xkey->serial) { key = xkey; rb = rb->rb_left; } else if (cursor > xkey->serial) { rb = rb->rb_right; } else { rb = rb_next(rb); if (!rb) goto reached_the_end; key = rb_entry(rb, struct key, serial_node); break; } } if (!key) goto reached_the_end; /* trawl through the keys looking for keyrings */ for (;;) { if (key->expiry > limit && key->expiry < new_timer) { kdebug("will expire %x in %ld", key_serial(key), key->expiry - limit); new_timer = key->expiry; } if (key->type == &key_type_keyring && key_gc_keyring(key, limit)) /* the gc had to release our lock so that the keyring * could be modified, so we have to get it again */ goto gc_released_our_lock; rb = rb_next(&key->serial_node); if (!rb) goto reached_the_end; key = rb_entry(rb, struct key, serial_node); } gc_released_our_lock: kdebug("gc_released_our_lock"); key_gc_new_timer = new_timer; key_gc_again = true; clear_bit(0, &key_gc_executing); schedule_work(&key_gc_work); kleave(" [continue]"); return; /* when we reach the end of the run, we set the timer for the next one */ reached_the_end: kdebug("reached_the_end"); spin_unlock(&key_serial_lock); key_gc_new_timer = new_timer; key_gc_cursor = 0; clear_bit(0, &key_gc_executing); if (key_gc_again) { /* there may have been a key that expired whilst we were * scanning, so if we discarded any links we should do another * scan */ new_timer = now + 1; key_schedule_gc(new_timer); } else if (new_timer < LONG_MAX) { new_timer += key_gc_delay; key_schedule_gc(new_timer); } kleave(" [end]"); }
/* * Install the user and user session keyrings for the current process's UID. */ int install_user_keyrings(void) { struct user_struct *user; const struct cred *cred; struct key *uid_keyring, *session_keyring; char buf[20]; int ret; cred = current_cred(); user = cred->user; kenter("%p{%u}", user, user->uid); if (user->uid_keyring && user->session_keyring) { kleave(" = 0 [exist]"); return 0; } mutex_lock(&key_user_keyring_mutex); ret = 0; if (!user->uid_keyring) { /* get the UID-specific keyring * - there may be one in existence already as it may have been * pinned by a session, but the user_struct pointing to it * may have been destroyed by setuid */ sprintf(buf, "_uid.%u", user->uid); uid_keyring = find_keyring_by_name(buf, true); if (IS_ERR(uid_keyring)) { uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, cred, KEY_ALLOC_IN_QUOTA, NULL); if (IS_ERR(uid_keyring)) { ret = PTR_ERR(uid_keyring); goto error; } } /* get a default session keyring (which might also exist * already) */ sprintf(buf, "_uid_ses.%u", user->uid); session_keyring = find_keyring_by_name(buf, true); if (IS_ERR(session_keyring)) { session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, cred, KEY_ALLOC_IN_QUOTA, NULL); if (IS_ERR(session_keyring)) { ret = PTR_ERR(session_keyring); goto error_release; } /* we install a link from the user session keyring to * the user keyring */ ret = key_link(session_keyring, uid_keyring); if (ret < 0) goto error_release_both; } /* install the keyrings */ user->uid_keyring = uid_keyring; user->session_keyring = session_keyring; } mutex_unlock(&key_user_keyring_mutex); kleave(" = 0"); return 0; error_release_both: key_put(session_keyring); error_release: key_put(uid_keyring); error: mutex_unlock(&key_user_keyring_mutex); kleave(" = %d", ret); return ret; }
/** * Check the trust on one PKCS#7 SignedInfo block. */ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, struct pkcs7_signed_info *sinfo, struct key *trust_keyring) { struct public_key_signature *sig = sinfo->sig; struct x509_certificate *x509, *last = NULL, *p; struct key *key; int ret; kenter(",%u,", sinfo->index); if (sinfo->unsupported_crypto) { kleave(" = -ENOPKG [cached]"); return -ENOPKG; } for (x509 = sinfo->signer; x509; x509 = x509->signer) { if (x509->seen) { if (x509->verified) goto verified; kleave(" = -ENOKEY [cached]"); return -ENOKEY; } x509->seen = true; /* Look to see if this certificate is present in the trusted * keys. */ key = find_asymmetric_key(trust_keyring, x509->id, x509->skid, false); if (!IS_ERR(key)) { /* One of the X.509 certificates in the PKCS#7 message * is apparently the same as one we already trust. * Verify that the trusted variant can also validate * the signature on the descendant. */ pr_devel("sinfo %u: Cert %u as key %x\n", sinfo->index, x509->index, key_serial(key)); goto matched; } if (key == ERR_PTR(-ENOMEM)) return -ENOMEM; /* Self-signed certificates form roots of their own, and if we * don't know them, then we can't accept them. */ if (x509->signer == x509) { kleave(" = -ENOKEY [unknown self-signed]"); return -ENOKEY; } might_sleep(); last = x509; sig = last->sig; } /* No match - see if the root certificate has a signer amongst the * trusted keys. */ if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) { key = find_asymmetric_key(trust_keyring, last->sig->auth_ids[0], last->sig->auth_ids[1], false); if (!IS_ERR(key)) { x509 = last; pr_devel("sinfo %u: Root cert %u signer is key %x\n", sinfo->index, x509->index, key_serial(key)); goto matched; } if (PTR_ERR(key) != -ENOKEY) return PTR_ERR(key); } /* As a last resort, see if we have a trusted public key that matches * the signed info directly. */ key = find_asymmetric_key(trust_keyring, sinfo->sig->auth_ids[0], NULL, false); if (!IS_ERR(key)) { pr_devel("sinfo %u: Direct signer is key %x\n", sinfo->index, key_serial(key)); x509 = NULL; goto matched; } if (PTR_ERR(key) != -ENOKEY) return PTR_ERR(key); kleave(" = -ENOKEY [no backref]"); return -ENOKEY; matched: ret = public_key_verify_signature(key->public_key, sig); key_put(key); if (ret < 0) { if (ret == -ENOMEM) return ret; kleave(" = -EKEYREJECTED [verify %d]", ret); return -EKEYREJECTED; } verified: if (x509) { x509->verified = true; for (p = sinfo->signer; p != x509; p = p->signer) p->verified = true; } kleave(" = 0"); return 0; }
/* * Get the appropriate destination keyring for the request. * * The keyring selected is returned with an extra reference upon it which the * caller must release. */ static void construct_get_dest_keyring(struct key **_dest_keyring) { struct request_key_auth *rka; const struct cred *cred = current_cred(); struct key *dest_keyring = *_dest_keyring, *authkey; kenter("%p", dest_keyring); /* find the appropriate keyring */ if (dest_keyring) { /* the caller supplied one */ key_get(dest_keyring); } else { /* use a default keyring; falling through the cases until we * find one that we actually have */ switch (cred->jit_keyring) { case KEY_REQKEY_DEFL_DEFAULT: case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: if (cred->request_key_auth) { authkey = cred->request_key_auth; down_read(&authkey->sem); rka = authkey->payload.data; if (!test_bit(KEY_FLAG_REVOKED, &authkey->flags)) dest_keyring = key_get(rka->dest_keyring); up_read(&authkey->sem); if (dest_keyring) break; } case KEY_REQKEY_DEFL_THREAD_KEYRING: dest_keyring = key_get(cred->thread_keyring); if (dest_keyring) break; case KEY_REQKEY_DEFL_PROCESS_KEYRING: dest_keyring = key_get(cred->tgcred->process_keyring); if (dest_keyring) break; case KEY_REQKEY_DEFL_SESSION_KEYRING: rcu_read_lock(); dest_keyring = key_get( rcu_dereference(cred->tgcred->session_keyring)); rcu_read_unlock(); if (dest_keyring) break; case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: dest_keyring = key_get(cred->user->session_keyring); break; case KEY_REQKEY_DEFL_USER_KEYRING: dest_keyring = key_get(cred->user->uid_keyring); break; case KEY_REQKEY_DEFL_GROUP_KEYRING: default: BUG(); } } *_dest_keyring = dest_keyring; kleave(" [dk %d]", key_serial(dest_keyring)); return; }
/* * create a vfsmount to be automounted */ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) { struct afs_super_info *super; struct vfsmount *mnt; struct page *page = NULL; size_t size; char *buf, *devname = NULL, *options = NULL; int ret; kenter("{%s}", mntpt->d_name.name); BUG_ON(!mntpt->d_inode); ret = -EINVAL; size = mntpt->d_inode->i_size; if (size > PAGE_SIZE - 1) goto error; ret = -ENOMEM; devname = (char *) get_zeroed_page(GFP_KERNEL); if (!devname) goto error; options = (char *) get_zeroed_page(GFP_KERNEL); if (!options) goto error; /* read the contents of the AFS special symlink */ page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto error; } ret = -EIO; wait_on_page_locked(page); if (!PageUptodate(page) || PageError(page)) goto error; buf = kmap(page); memcpy(devname, buf, size); kunmap(page); page_cache_release(page); page = NULL; /* work out what options we want */ super = AFS_FS_S(mntpt->d_sb); memcpy(options, "cell=", 5); strcpy(options + 5, super->volume->cell->name); if (super->volume->type == AFSVL_RWVOL) strcat(options, ",rwpath"); /* try and do the mount */ kdebug("--- attempting mount %s -o %s ---", devname, options); mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); kdebug("--- mount result %p ---", mnt); free_page((unsigned long) devname); free_page((unsigned long) options); kleave(" = %p", mnt); return mnt; error: if (page) page_cache_release(page); if (devname) free_page((unsigned long) devname); if (options) free_page((unsigned long) options); kleave(" = %d", ret); return ERR_PTR(ret); } /* end afs_mntpt_do_automount() */
/** * Check the trust on one PKCS#7 SignedInfo block. */ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, struct pkcs7_signed_info *sinfo, struct key *trust_keyring) { struct public_key_signature *sig = &sinfo->sig; struct x509_certificate *x509, *last = NULL, *p; struct key *key; bool trusted; int ret; kenter(",%u,", sinfo->index); for (x509 = sinfo->signer; x509; x509 = x509->signer) { if (x509->seen) { if (x509->verified) { trusted = x509->trusted; goto verified; } kleave(" = -ENOKEY [cached]"); return -ENOKEY; } x509->seen = true; /* Look to see if this certificate is present in the trusted * keys. */ key = pkcs7_request_asymmetric_key( trust_keyring, x509->subject, strlen(x509->subject), x509->fingerprint, strlen(x509->fingerprint)); if (!IS_ERR(key)) /* One of the X.509 certificates in the PKCS#7 message * is apparently the same as one we already trust. * Verify that the trusted variant can also validate * the signature on the descendant. */ goto matched; if (key == ERR_PTR(-ENOMEM)) return -ENOMEM; /* Self-signed certificates form roots of their own, and if we * don't know them, then we can't accept them. */ if (x509->next == x509) { kleave(" = -ENOKEY [unknown self-signed]"); return -ENOKEY; } might_sleep(); last = x509; sig = &last->sig; } /* No match - see if the root certificate has a signer amongst the * trusted keys. */ if (!last || !last->issuer || !last->authority) { kleave(" = -ENOKEY [no backref]"); return -ENOKEY; } key = pkcs7_request_asymmetric_key( trust_keyring, last->issuer, strlen(last->issuer), last->authority, strlen(last->authority)); if (IS_ERR(key)) return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY; x509 = last; matched: ret = verify_signature(key, sig); trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); key_put(key); if (ret < 0) { if (ret == -ENOMEM) return ret; kleave(" = -EKEYREJECTED [verify %d]", ret); return -EKEYREJECTED; } verified: x509->verified = true; for (p = sinfo->signer; p != x509; p = p->signer) { p->verified = true; p->trusted = trusted; } sinfo->trusted = trusted; kleave(" = 0"); return 0; }
int afs_rxfs_lookup(struct afs_server *server, struct afs_vnode *dir, const char *filename, struct afs_vnode *vnode, struct afs_volsync *volsync) { struct rxrpc_connection *conn; struct rxrpc_call *call; struct kvec piov[3]; size_t sent; int ret; u32 *bp, zero; DECLARE_WAITQUEUE(myself, current); kenter("%p,{%u,%u,%u},%s", server, fid->vid, fid->vnode, fid->unique, filename); /* get hold of the fileserver connection */ ret = afs_server_get_fsconn(server, &conn); if (ret < 0) goto out; /* create a call through that connection */ ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call); if (ret < 0) { printk("kAFS: Unable to create call: %d\n", ret); goto out_put_conn; } call->app_opcode = FSLOOKUP; /* we want to get event notifications from the call */ add_wait_queue(&call->waitq,&myself); /* marshall the parameters */ bp = rxrpc_call_alloc_scratch(call, 20); zero = 0; piov[0].iov_len = 20; piov[0].iov_base = bp; piov[1].iov_len = strlen(filename); piov[1].iov_base = (char *) filename; piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3; piov[2].iov_base = &zero; *bp++ = htonl(FSLOOKUP); *bp++ = htonl(dirfid->vid); *bp++ = htonl(dirfid->vnode); *bp++ = htonl(dirfid->unique); *bp++ = htonl(piov[1].iov_len); /* send the parameters to the server */ ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS, 0, &sent); if (ret < 0) goto abort; /* wait for the reply to completely arrive */ bp = rxrpc_call_alloc_scratch(call, 220); ret = rxrpc_call_read_data(call, bp, 220, RXRPC_CALL_READ_BLOCK | RXRPC_CALL_READ_ALL); if (ret < 0) { if (ret == -ECONNABORTED) { ret = call->app_errno; goto out_unwait; } goto abort; } /* unmarshall the reply */ fid->vid = ntohl(*bp++); fid->vnode = ntohl(*bp++); fid->unique = ntohl(*bp++); vnode->status.if_version = ntohl(*bp++); vnode->status.type = ntohl(*bp++); vnode->status.nlink = ntohl(*bp++); vnode->status.size = ntohl(*bp++); vnode->status.version = ntohl(*bp++); vnode->status.author = ntohl(*bp++); vnode->status.owner = ntohl(*bp++); vnode->status.caller_access = ntohl(*bp++); vnode->status.anon_access = ntohl(*bp++); vnode->status.mode = ntohl(*bp++); vnode->status.parent.vid = dirfid->vid; vnode->status.parent.vnode = ntohl(*bp++); vnode->status.parent.unique = ntohl(*bp++); bp++; /* seg size */ vnode->status.mtime_client = ntohl(*bp++); vnode->status.mtime_server = ntohl(*bp++); bp++; /* group */ bp++; /* sync counter */ vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32; bp++; /* spare2 */ bp++; /* spare3 */ bp++; /* spare4 */ dir->status.if_version = ntohl(*bp++); dir->status.type = ntohl(*bp++); dir->status.nlink = ntohl(*bp++); dir->status.size = ntohl(*bp++); dir->status.version = ntohl(*bp++); dir->status.author = ntohl(*bp++); dir->status.owner = ntohl(*bp++); dir->status.caller_access = ntohl(*bp++); dir->status.anon_access = ntohl(*bp++); dir->status.mode = ntohl(*bp++); dir->status.parent.vid = dirfid->vid; dir->status.parent.vnode = ntohl(*bp++); dir->status.parent.unique = ntohl(*bp++); bp++; /* seg size */ dir->status.mtime_client = ntohl(*bp++); dir->status.mtime_server = ntohl(*bp++); bp++; /* group */ bp++; /* sync counter */ dir->status.version |= ((unsigned long long) ntohl(*bp++)) << 32; bp++; /* spare2 */ bp++; /* spare3 */ bp++; /* spare4 */ callback->fid = *fid; callback->version = ntohl(*bp++); callback->expiry = ntohl(*bp++); callback->type = ntohl(*bp++); if (volsync) { volsync->creation = ntohl(*bp++); bp++; /* spare2 */ bp++; /* spare3 */ bp++; /* spare4 */ bp++; /* spare5 */ bp++; /* spare6 */ } /* success */ ret = 0; out_unwait: set_current_state(TASK_RUNNING); remove_wait_queue(&call->waitq, &myself); rxrpc_put_call(call); out_put_conn: afs_server_release_fsconn(server, conn); out: kleave(""); return ret; abort: set_current_state(TASK_UNINTERRUPTIBLE); rxrpc_call_abort(call, ret); schedule(); goto out_unwait; } /* end afs_rxfs_lookup() */
/* * Garbage collector for unused keys. * * This is done in process context so that we don't have to disable interrupts * all over the place. key_put() schedules this rather than trying to do the * cleanup itself, which means key_put() doesn't have to sleep. */ static void key_garbage_collector(struct work_struct *work) { static LIST_HEAD(graveyard); static u8 gc_state; /* Internal persistent state */ #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ #define KEY_GC_SET_TIMER 0x04 /* - We need to restart the timer */ #define KEY_GC_REAPING_DEAD_1 0x10 /* - We need to mark dead keys */ #define KEY_GC_REAPING_DEAD_2 0x20 /* - We need to reap dead key links */ #define KEY_GC_REAPING_DEAD_3 0x40 /* - We need to reap dead keys */ #define KEY_GC_FOUND_DEAD_KEY 0x80 /* - We found at least one dead key */ struct rb_node *cursor; struct key *key; time_t new_timer, limit; kenter("[%lx,%x]", key_gc_flags, gc_state); limit = current_kernel_time().tv_sec; if (limit > key_gc_delay) limit -= key_gc_delay; else limit = key_gc_delay; /* Work out what we're going to be doing in this pass */ gc_state &= KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2; gc_state <<= 1; if (test_and_clear_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags)) gc_state |= KEY_GC_REAPING_LINKS | KEY_GC_SET_TIMER; if (test_and_clear_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) gc_state |= KEY_GC_REAPING_DEAD_1; kdebug("new pass %x", gc_state); new_timer = LONG_MAX; /* As only this function is permitted to remove things from the key * serial tree, if cursor is non-NULL then it will always point to a * valid node in the tree - even if lock got dropped. */ spin_lock(&key_serial_lock); cursor = rb_first(&key_serial_tree); continue_scanning: while (cursor) { key = rb_entry(cursor, struct key, serial_node); cursor = rb_next(cursor); if (atomic_read(&key->usage) == 0) goto found_unreferenced_key; if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { if (key->type == key_gc_dead_keytype) { gc_state |= KEY_GC_FOUND_DEAD_KEY; set_bit(KEY_FLAG_DEAD, &key->flags); key->perm = 0; goto skip_dead_key; } } if (gc_state & KEY_GC_SET_TIMER) { if (key->expiry > limit && key->expiry < new_timer) { kdebug("will expire %x in %ld", key_serial(key), key->expiry - limit); new_timer = key->expiry; } } if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) if (key->type == key_gc_dead_keytype) gc_state |= KEY_GC_FOUND_DEAD_KEY; if ((gc_state & KEY_GC_REAPING_LINKS) || unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { if (key->type == &key_type_keyring) goto found_keyring; } if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) if (key->type == key_gc_dead_keytype) goto destroy_dead_key; skip_dead_key: if (spin_is_contended(&key_serial_lock) || need_resched()) goto contended; } contended: spin_unlock(&key_serial_lock); maybe_resched: if (cursor) { cond_resched(); spin_lock(&key_serial_lock); goto continue_scanning; } /* We've completed the pass. Set the timer if we need to and queue a * new cycle if necessary. We keep executing cycles until we find one * where we didn't reap any keys. */ kdebug("pass complete"); if (gc_state & KEY_GC_SET_TIMER && new_timer != (time_t)LONG_MAX) { new_timer += key_gc_delay; key_schedule_gc(new_timer); } if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2) || !list_empty(&graveyard)) { /* Make sure that all pending keyring payload destructions are * fulfilled and that people aren't now looking at dead or * dying keys that they don't have a reference upon or a link * to. */ kdebug("gc sync"); synchronize_rcu(); } if (!list_empty(&graveyard)) { kdebug("gc keys"); key_gc_unused_keys(&graveyard); } if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2))) { if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { /* No remaining dead keys: short circuit the remaining * keytype reap cycles. */ kdebug("dead short"); gc_state &= ~(KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2); gc_state |= KEY_GC_REAPING_DEAD_3; } else { gc_state |= KEY_GC_REAP_AGAIN; } } if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) { kdebug("dead wake"); smp_mb(); clear_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); wake_up_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE); } if (gc_state & KEY_GC_REAP_AGAIN) schedule_work(&key_gc_work); kleave(" [end %x]", gc_state); return; /* We found an unreferenced key - once we've removed it from the tree, * we can safely drop the lock. */ found_unreferenced_key: kdebug("unrefd key %d", key->serial); rb_erase(&key->serial_node, &key_serial_tree); spin_unlock(&key_serial_lock); list_add_tail(&key->graveyard_link, &graveyard); gc_state |= KEY_GC_REAP_AGAIN; goto maybe_resched; /* We found a keyring and we need to check the payload for links to * dead or expired keys. We don't flag another reap immediately as we * have to wait for the old payload to be destroyed by RCU before we * can reap the keys to which it refers. */ found_keyring: spin_unlock(&key_serial_lock); kdebug("scan keyring %d", key->serial); key_gc_keyring(key, limit); goto maybe_resched; /* We found a dead key that is still referenced. Reset its type and * destroy its payload with its semaphore held. */ destroy_dead_key: spin_unlock(&key_serial_lock); kdebug("destroy key %d", key->serial); down_write(&key->sem); key->type = &key_type_dead; if (key_gc_dead_keytype->destroy) key_gc_dead_keytype->destroy(key); memset(&key->payload, KEY_DESTROY, sizeof(key->payload)); up_write(&key->sem); goto maybe_resched; }
/* * 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 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; kenter("%d,", target->serial); /* allocate a auth record */ rka = kmalloc(sizeof(*rka), GFP_KERNEL); if (!rka) { kleave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); } rka->callout_info = kmalloc(callout_len, GFP_KERNEL); if (!rka->callout_info) { kleave(" = -ENOMEM"); kfree(rka); return ERR_PTR(-ENOMEM); } /* 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)) goto auth_key_revoked; irka = cred->request_key_auth->payload.data; 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); memcpy(rka->callout_info, callout_info, callout_len); rka->callout_len = callout_len; /* 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_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA); if (IS_ERR(authkey)) { ret = PTR_ERR(authkey); goto error_alloc; } /* construct the auth key */ ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); if (ret < 0) goto error_inst; kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); return authkey; auth_key_revoked: up_read(&cred->request_key_auth->sem); kfree(rka->callout_info); kfree(rka); kleave("= -EKEYREVOKED"); return ERR_PTR(-EKEYREVOKED); error_inst: key_revoke(authkey); key_put(authkey); error_alloc: key_put(rka->target_key); key_put(rka->dest_keyring); kfree(rka->callout_info); kfree(rka); kleave("= %d", ret); return ERR_PTR(ret); } /* end request_key_auth_new() */
int afs_rxfs_get_root_volume(struct afs_server *server, char *buf, size_t *buflen) { struct rxrpc_connection *conn; struct rxrpc_call *call; struct kvec piov[2]; size_t sent; int ret; u32 param[1]; DECLARE_WAITQUEUE(myself, current); kenter("%p,%p,%u",server, buf, *buflen); /* get hold of the fileserver connection */ ret = afs_server_get_fsconn(server, &conn); if (ret < 0) goto out; /* create a call through that connection */ ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call); if (ret < 0) { printk("kAFS: Unable to create call: %d\n", ret); goto out_put_conn; } call->app_opcode = FSGETROOTVOLUME; /* we want to get event notifications from the call */ add_wait_queue(&call->waitq, &myself); /* marshall the parameters */ param[0] = htonl(FSGETROOTVOLUME); piov[0].iov_len = sizeof(param); piov[0].iov_base = param; /* send the parameters to the server */ ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS, 0, &sent); if (ret < 0) goto abort; /* wait for the reply to completely arrive */ for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY || signal_pending(current)) break; schedule(); } set_current_state(TASK_RUNNING); ret = -EINTR; if (signal_pending(current)) goto abort; switch (call->app_call_state) { case RXRPC_CSTATE_ERROR: ret = call->app_errno; kdebug("Got Error: %d", ret); goto out_unwait; case RXRPC_CSTATE_CLNT_GOT_REPLY: /* read the reply */ kdebug("Got Reply: qty=%d", call->app_ready_qty); ret = -EBADMSG; if (call->app_ready_qty <= 4) goto abort; ret = rxrpc_call_read_data(call, NULL, call->app_ready_qty, 0); if (ret < 0) goto abort; #if 0 /* unmarshall the reply */ bp = buffer; for (loop = 0; loop < 65; loop++) entry->name[loop] = ntohl(*bp++); entry->name[64] = 0; entry->type = ntohl(*bp++); entry->num_servers = ntohl(*bp++); for (loop = 0; loop < 8; loop++) entry->servers[loop].addr.s_addr = *bp++; for (loop = 0; loop < 8; loop++) entry->servers[loop].partition = ntohl(*bp++); for (loop = 0; loop < 8; loop++) entry->servers[loop].flags = ntohl(*bp++); for (loop = 0; loop < 3; loop++) entry->volume_ids[loop] = ntohl(*bp++); entry->clone_id = ntohl(*bp++); entry->flags = ntohl(*bp); #endif /* success */ ret = 0; goto out_unwait; default: BUG(); } abort: set_current_state(TASK_UNINTERRUPTIBLE); rxrpc_call_abort(call, ret); schedule(); out_unwait: set_current_state(TASK_RUNNING); remove_wait_queue(&call->waitq, &myself); rxrpc_put_call(call); out_put_conn: afs_server_release_fsconn(server, conn); out: kleave(""); return ret; } /* end afs_rxfs_get_root_volume() */