Commit 61d335dd authored by James Morris's avatar James Morris

Merge branch 'security-next-keys' of...

Merge branch 'security-next-keys' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/security-keys into next-queue

As requested by David.
parents 87b526d3 4442d770
...@@ -412,6 +412,10 @@ The main syscalls are: ...@@ -412,6 +412,10 @@ The main syscalls are:
to the keyring. In this case, an error will be generated if the process to the keyring. In this case, an error will be generated if the process
does not have permission to write to the keyring. does not have permission to write to the keyring.
If the key type supports it, if the description is NULL or an empty
string, the key type will try and generate a description from the content
of the payload.
The payload is optional, and the pointer can be NULL if not required by The payload is optional, and the pointer can be NULL if not required by
the type. The payload is plen in size, and plen can be zero for an empty the type. The payload is plen in size, and plen can be zero for an empty
payload. payload.
...@@ -990,6 +994,23 @@ payload contents" for more information. ...@@ -990,6 +994,23 @@ payload contents" for more information.
reference pointer if successful. reference pointer if successful.
(*) A keyring can be created by:
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred,
key_perm_t perm,
unsigned long flags,
struct key *dest);
This creates a keyring with the given attributes and returns it. If dest
is not NULL, the new keyring will be linked into the keyring to which it
points. No permission checks are made upon the destination keyring.
Error EDQUOT can be returned if the keyring would overload the quota (pass
KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
towards the user's quota). Error ENOMEM can also be returned.
(*) To check the validity of a key, this function can be called: (*) To check the validity of a key, this function can be called:
int validate_key(struct key *key); int validate_key(struct key *key);
...@@ -1114,12 +1135,53 @@ The structure has a number of fields, some of which are mandatory: ...@@ -1114,12 +1135,53 @@ The structure has a number of fields, some of which are mandatory:
it should return 0. it should return 0.
(*) int (*instantiate)(struct key *key, const void *data, size_t datalen); (*) int (*preparse)(struct key_preparsed_payload *prep);
This optional method permits the key type to attempt to parse payload
before a key is created (add key) or the key semaphore is taken (update or
instantiate key). The structure pointed to by prep looks like:
struct key_preparsed_payload {
char *description;
void *type_data[2];
void *payload;
const void *data;
size_t datalen;
size_t quotalen;
};
Before calling the method, the caller will fill in data and datalen with
the payload blob parameters; quotalen will be filled in with the default
quota size from the key type and the rest will be cleared.
If a description can be proposed from the payload contents, that should be
attached as a string to the description field. This will be used for the
key description if the caller of add_key() passes NULL or "".
The method can attach anything it likes to type_data[] and payload. These
are merely passed along to the instantiate() or update() operations.
The method should return 0 if success ful or a negative error code
otherwise.
(*) void (*free_preparse)(struct key_preparsed_payload *prep);
This method is only required if the preparse() method is provided,
otherwise it is unused. It cleans up anything attached to the
description, type_data and payload fields of the key_preparsed_payload
struct as filled in by the preparse() method.
(*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
This method is called to attach a payload to a key during construction. This method is called to attach a payload to a key during construction.
The payload attached need not bear any relation to the data passed to this The payload attached need not bear any relation to the data passed to this
function. function.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
If the amount of data attached to the key differs from the size in If the amount of data attached to the key differs from the size in
keytype->def_datalen, then key_payload_reserve() should be called. keytype->def_datalen, then key_payload_reserve() should be called.
...@@ -1135,6 +1197,9 @@ The structure has a number of fields, some of which are mandatory: ...@@ -1135,6 +1197,9 @@ The structure has a number of fields, some of which are mandatory:
If this type of key can be updated, then this method should be provided. If this type of key can be updated, then this method should be provided.
It is called to update a key's payload from the blob of data provided. It is called to update a key's payload from the blob of data provided.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
key_payload_reserve() should be called if the data length might change key_payload_reserve() should be called if the data length might change
before any changes are actually made. Note that if this succeeds, the type before any changes are actually made. Note that if this succeeds, the type
is committed to changing the key because it's already been altered, so all is committed to changing the key because it's already been altered, so all
......
...@@ -31,18 +31,18 @@ ...@@ -31,18 +31,18 @@
/* create a new cifs key */ /* create a new cifs key */
static int static int
cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen) cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{ {
char *payload; char *payload;
int ret; int ret;
ret = -ENOMEM; ret = -ENOMEM;
payload = kmalloc(datalen, GFP_KERNEL); payload = kmalloc(prep->datalen, GFP_KERNEL);
if (!payload) if (!payload)
goto error; goto error;
/* attach the data */ /* attach the data */
memcpy(payload, data, datalen); memcpy(payload, prep->data, prep->datalen);
key->payload.data = payload; key->payload.data = payload;
ret = 0; ret = 0;
......
...@@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = { ...@@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = {
}; };
static int static int
cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{ {
char *payload; char *payload;
payload = kmalloc(datalen, GFP_KERNEL); payload = kmalloc(prep->datalen, GFP_KERNEL);
if (!payload) if (!payload)
return -ENOMEM; return -ENOMEM;
memcpy(payload, data, datalen); memcpy(payload, prep->data, prep->datalen);
key->payload.data = payload; key->payload.data = payload;
key->datalen = datalen; key->datalen = prep->datalen;
return 0; return 0;
} }
...@@ -537,19 +537,15 @@ init_cifs_idmap(void) ...@@ -537,19 +537,15 @@ init_cifs_idmap(void)
if (!cred) if (!cred)
return -ENOMEM; return -ENOMEM;
keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, keyring = keyring_alloc(".cifs_idmap", 0, 0, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ, KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA); KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto failed_put_cred; goto failed_put_cred;
} }
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
if (ret < 0)
goto failed_put_key;
ret = register_key_type(&cifs_idmap_key_type); ret = register_key_type(&cifs_idmap_key_type);
if (ret < 0) if (ret < 0)
goto failed_put_key; goto failed_put_key;
......
...@@ -192,19 +192,15 @@ static int nfs_idmap_init_keyring(void) ...@@ -192,19 +192,15 @@ static int nfs_idmap_init_keyring(void)
if (!cred) if (!cred)
return -ENOMEM; return -ENOMEM;
keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred, keyring = keyring_alloc(".id_resolver", 0, 0, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ, KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA); KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto failed_put_cred; goto failed_put_cred;
} }
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
if (ret < 0)
goto failed_put_key;
ret = register_key_type(&key_type_id_resolver); ret = register_key_type(&key_type_id_resolver);
if (ret < 0) if (ret < 0)
goto failed_put_key; goto failed_put_key;
......
...@@ -35,8 +35,10 @@ struct user_key_payload { ...@@ -35,8 +35,10 @@ struct user_key_payload {
extern struct key_type key_type_user; extern struct key_type key_type_user;
extern struct key_type key_type_logon; extern struct key_type key_type_logon;
extern int user_instantiate(struct key *key, const void *data, size_t datalen); struct key_preparsed_payload;
extern int user_update(struct key *key, const void *data, size_t datalen);
extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep);
extern int user_update(struct key *key, struct key_preparsed_payload *prep);
extern int user_match(const struct key *key, const void *criterion); extern int user_match(const struct key *key, const void *criterion);
extern void user_revoke(struct key *key); extern void user_revoke(struct key *key);
extern void user_destroy(struct key *key); extern void user_destroy(struct key *key);
......
...@@ -76,21 +76,6 @@ extern int groups_search(const struct group_info *, kgid_t); ...@@ -76,21 +76,6 @@ extern int groups_search(const struct group_info *, kgid_t);
extern int in_group_p(kgid_t); extern int in_group_p(kgid_t);
extern int in_egroup_p(kgid_t); extern int in_egroup_p(kgid_t);
/*
* The common credentials for a thread group
* - shared by CLONE_THREAD
*/
#ifdef CONFIG_KEYS
struct thread_group_cred {
atomic_t usage;
pid_t tgid; /* thread group process ID */
spinlock_t lock;
struct key __rcu *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
struct rcu_head rcu; /* RCU deletion hook */
};
#endif
/* /*
* The security context of a task * The security context of a task
* *
...@@ -139,6 +124,8 @@ struct cred { ...@@ -139,6 +124,8 @@ struct cred {
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
unsigned char jit_keyring; /* default keyring to attach requested unsigned char jit_keyring; /* default keyring to attach requested
* keys to */ * keys to */
struct key __rcu *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
struct key *thread_keyring; /* keyring private to this thread */ struct key *thread_keyring; /* keyring private to this thread */
struct key *request_key_auth; /* assumed request_key authority */ struct key *request_key_auth; /* assumed request_key authority */
struct thread_group_cred *tgcred; /* thread-group shared credentials */ struct thread_group_cred *tgcred; /* thread-group shared credentials */
......
...@@ -26,6 +26,27 @@ struct key_construction { ...@@ -26,6 +26,27 @@ struct key_construction {
struct key *authkey;/* authorisation for key being constructed */ struct key *authkey;/* authorisation for key being constructed */
}; };
/*
* Pre-parsed payload, used by key add, update and instantiate.
*
* This struct will be cleared and data and datalen will be set with the data
* and length parameters from the caller and quotalen will be set from
* def_datalen from the key type. Then if the preparse() op is provided by the
* key type, that will be called. Then the struct will be passed to the
* instantiate() or the update() op.
*
* If the preparse() op is given, the free_preparse() op will be called to
* clear the contents.
*/
struct key_preparsed_payload {
char *description; /* Proposed key description (or NULL) */
void *type_data[2]; /* Private key-type data */
void *payload; /* Proposed payload */
const void *data; /* Raw data */
size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */
};
typedef int (*request_key_actor_t)(struct key_construction *key, typedef int (*request_key_actor_t)(struct key_construction *key,
const char *op, void *aux); const char *op, void *aux);
...@@ -45,18 +66,28 @@ struct key_type { ...@@ -45,18 +66,28 @@ struct key_type {
/* vet a description */ /* vet a description */
int (*vet_description)(const char *description); int (*vet_description)(const char *description);
/* Preparse the data blob from userspace that is to be the payload,
* generating a proposed description and payload that will be handed to
* the instantiate() and update() ops.
*/
int (*preparse)(struct key_preparsed_payload *prep);
/* Free a preparse data structure.
*/
void (*free_preparse)(struct key_preparsed_payload *prep);
/* instantiate a key of this type /* instantiate a key of this type
* - this method should call key_payload_reserve() to determine if the * - this method should call key_payload_reserve() to determine if the
* user's quota will hold the payload * user's quota will hold the payload
*/ */
int (*instantiate)(struct key *key, const void *data, size_t datalen); int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
/* update a key of this type (optional) /* update a key of this type (optional)
* - this method should call key_payload_reserve() to recalculate the * - this method should call key_payload_reserve() to recalculate the
* quota consumption * quota consumption
* - the key must be locked against read when modifying * - the key must be locked against read when modifying
*/ */
int (*update)(struct key *key, const void *data, size_t datalen); int (*update)(struct key *key, struct key_preparsed_payload *prep);
/* match a key against a description */ /* match a key against a description */
int (*match)(const struct key *key, const void *desc); int (*match)(const struct key *key, const void *desc);
......
...@@ -264,6 +264,7 @@ extern int key_unlink(struct key *keyring, ...@@ -264,6 +264,7 @@ extern int key_unlink(struct key *keyring,
extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred, const struct cred *cred,
key_perm_t perm,
unsigned long flags, unsigned long flags,
struct key *dest); struct key *dest);
......
...@@ -29,17 +29,6 @@ ...@@ -29,17 +29,6 @@
static struct kmem_cache *cred_jar; static struct kmem_cache *cred_jar;
/*
* The common credentials for the initial task's thread group
*/
#ifdef CONFIG_KEYS
static struct thread_group_cred init_tgcred = {
.usage = ATOMIC_INIT(2),
.tgid = 0,
.lock = __SPIN_LOCK_UNLOCKED(init_cred.tgcred.lock),
};
#endif
/* /*
* The initial credentials for the initial task * The initial credentials for the initial task
*/ */
...@@ -65,9 +54,6 @@ struct cred init_cred = { ...@@ -65,9 +54,6 @@ struct cred init_cred = {
.user = INIT_USER, .user = INIT_USER,
.user_ns = &init_user_ns, .user_ns = &init_user_ns,
.group_info = &init_groups, .group_info = &init_groups,
#ifdef CONFIG_KEYS
.tgcred = &init_tgcred,
#endif
}; };
static inline void set_cred_subscribers(struct cred *cred, int n) static inline void set_cred_subscribers(struct cred *cred, int n)
...@@ -95,36 +81,6 @@ static inline void alter_cred_subscribers(const struct cred *_cred, int n) ...@@ -95,36 +81,6 @@ static inline void alter_cred_subscribers(const struct cred *_cred, int n)
#endif #endif
} }
/*
* Dispose of the shared task group credentials
*/
#ifdef CONFIG_KEYS
static void release_tgcred_rcu(struct rcu_head *rcu)
{
struct thread_group_cred *tgcred =
container_of(rcu, struct thread_group_cred, rcu);
BUG_ON(atomic_read(&tgcred->usage) != 0);
key_put(tgcred->session_keyring);
key_put(tgcred->process_keyring);
kfree(tgcred);
}
#endif
/*
* Release a set of thread group credentials.
*/
static void release_tgcred(struct cred *cred)
{
#ifdef CONFIG_KEYS
struct thread_group_cred *tgcred = cred->tgcred;
if (atomic_dec_and_test(&tgcred->usage))
call_rcu(&tgcred->rcu, release_tgcred_rcu);
#endif
}
/* /*
* The RCU callback to actually dispose of a set of credentials * The RCU callback to actually dispose of a set of credentials
*/ */
...@@ -150,9 +106,10 @@ static void put_cred_rcu(struct rcu_head *rcu) ...@@ -150,9 +106,10 @@ static void put_cred_rcu(struct rcu_head *rcu)
#endif #endif
security_cred_free(cred); security_cred_free(cred);
key_put(cred->session_keyring);
key_put(cred->process_keyring);
key_put(cred->thread_keyring); key_put(cred->thread_keyring);
key_put(cred->request_key_auth); key_put(cred->request_key_auth);
release_tgcred(cred);
if (cred->group_info) if (cred->group_info)
put_group_info(cred->group_info); put_group_info(cred->group_info);
free_uid(cred->user); free_uid(cred->user);
...@@ -246,15 +203,6 @@ struct cred *cred_alloc_blank(void) ...@@ -246,15 +203,6 @@ struct cred *cred_alloc_blank(void)
if (!new) if (!new)
return NULL; return NULL;
#ifdef CONFIG_KEYS
new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL);
if (!new->tgcred) {
kmem_cache_free(cred_jar, new);
return NULL;
}
atomic_set(&new->tgcred->usage, 1);
#endif
atomic_set(&new->usage, 1); atomic_set(&new->usage, 1);
#ifdef CONFIG_DEBUG_CREDENTIALS #ifdef CONFIG_DEBUG_CREDENTIALS
new->magic = CRED_MAGIC; new->magic = CRED_MAGIC;
...@@ -308,9 +256,10 @@ struct cred *prepare_creds(void) ...@@ -308,9 +256,10 @@ struct cred *prepare_creds(void)
get_user_ns(new->user_ns); get_user_ns(new->user_ns);
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
key_get(new->session_keyring);
key_get(new->process_keyring);
key_get(new->thread_keyring); key_get(new->thread_keyring);
key_get(new->request_key_auth); key_get(new->request_key_auth);
atomic_inc(&new->tgcred->usage);
#endif #endif
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
...@@ -334,39 +283,20 @@ EXPORT_SYMBOL(prepare_creds); ...@@ -334,39 +283,20 @@ EXPORT_SYMBOL(prepare_creds);
*/ */
struct cred *prepare_exec_creds(void) struct cred *prepare_exec_creds(void)
{ {
struct thread_group_cred *tgcred = NULL;
struct cred *new; struct cred *new;
#ifdef CONFIG_KEYS
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
if (!tgcred)
return NULL;
#endif
new = prepare_creds(); new = prepare_creds();
if (!new) { if (!new)
kfree(tgcred);
return new; return new;
}
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
/* newly exec'd tasks don't get a thread keyring */ /* newly exec'd tasks don't get a thread keyring */
key_put(new->thread_keyring); key_put(new->thread_keyring);
new->thread_keyring = NULL; new->thread_keyring = NULL;
/* create a new per-thread-group creds for all this set of threads to
* share */
memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
atomic_set(&tgcred->usage, 1);
spin_lock_init(&tgcred->lock);
/* inherit the session keyring; new process keyring */ /* inherit the session keyring; new process keyring */
key_get(tgcred->session_keyring); key_put(new->process_keyring);
tgcred->process_keyring = NULL; new->process_keyring = NULL;
release_tgcred(new);
new->tgcred = tgcred;
#endif #endif
return new; return new;
...@@ -383,9 +313,6 @@ struct cred *prepare_exec_creds(void) ...@@ -383,9 +313,6 @@ struct cred *prepare_exec_creds(void)
*/ */
int copy_creds(struct task_struct *p, unsigned long clone_flags) int copy_creds(struct task_struct *p, unsigned long clone_flags)
{ {
#ifdef CONFIG_KEYS
struct thread_group_cred *tgcred;
#endif
struct cred *new; struct cred *new;
int ret; int ret;
...@@ -425,22 +352,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) ...@@ -425,22 +352,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
install_thread_keyring_to_cred(new); install_thread_keyring_to_cred(new);
} }
/* we share the process and session keyrings between all the threads in /* The process keyring is only shared between the threads in a process;
* a process - this is slightly icky as we violate COW credentials a * anything outside of those threads doesn't inherit.
* bit */ */
if (!(clone_flags & CLONE_THREAD)) { if (!(clone_flags & CLONE_THREAD)) {
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); key_put(new->process_keyring);
if (!tgcred) { new->process_keyring = NULL;
ret = -ENOMEM;
goto error_put;
}
atomic_set(&tgcred->usage, 1);
spin_lock_init(&tgcred->lock);
tgcred->process_keyring = NULL;
tgcred->session_keyring = key_get(new->tgcred->session_keyring);
release_tgcred(new);
new->tgcred = tgcred;
} }
#endif #endif
...@@ -643,9 +560,6 @@ void __init cred_init(void) ...@@ -643,9 +560,6 @@ void __init cred_init(void)
*/ */
struct cred *prepare_kernel_cred(struct task_struct *daemon) struct cred *prepare_kernel_cred(struct task_struct *daemon)
{ {
#ifdef CONFIG_KEYS
struct thread_group_cred *tgcred;
#endif
const struct cred *old; const struct cred *old;
struct cred *new; struct cred *new;
...@@ -653,14 +567,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) ...@@ -653,14 +567,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
if (!new) if (!new)
return NULL; return NULL;
#ifdef CONFIG_KEYS
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
if (!tgcred) {
kmem_cache_free(cred_jar, new);
return NULL;
}
#endif
kdebug("prepare_kernel_cred() alloc %p", new); kdebug("prepare_kernel_cred() alloc %p", new);
if (daemon) if (daemon)
...@@ -678,13 +584,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) ...@@ -678,13 +584,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
get_group_info(new->group_info); get_group_info(new->group_info);
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
atomic_set(&tgcred->usage, 1); new->session_keyring = NULL;
spin_lock_init(&tgcred->lock); new->process_keyring = NULL;
tgcred->process_keyring = NULL;
tgcred->session_keyring = NULL;
new->tgcred = tgcred;
new->request_key_auth = NULL;
new->thread_keyring = NULL; new->thread_keyring = NULL;
new->request_key_auth = NULL;
new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
#endif #endif
......
...@@ -423,14 +423,15 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, ...@@ -423,14 +423,15 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
} }
} }
int ceph_key_instantiate(struct key *key, const void *data, size_t datalen) int ceph_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{ {
struct ceph_crypto_key *ckey; struct ceph_crypto_key *ckey;
size_t datalen = prep->datalen;
int ret; int ret;
void *p; void *p;
ret = -EINVAL; ret = -EINVAL;
if (datalen <= 0 || datalen > 32767 || !data) if (datalen <= 0 || datalen > 32767 || !prep->data)
goto err; goto err;
ret = key_payload_reserve(key, datalen); ret = key_payload_reserve(key, datalen);
...@@ -443,8 +444,8 @@ int ceph_key_instantiate(struct key *key, const void *data, size_t datalen) ...@@ -443,8 +444,8 @@ int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
goto err; goto err;
/* TODO ceph_crypto_key_decode should really take const input */ /* TODO ceph_crypto_key_decode should really take const input */
p = (void *)data; p = (void *)prep->data;
ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen); ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
if (ret < 0) if (ret < 0)
goto err_ckey; goto err_ckey;
......
...@@ -59,13 +59,13 @@ const struct cred *dns_resolver_cache; ...@@ -59,13 +59,13 @@ const struct cred *dns_resolver_cache;
* "ip1,ip2,...#foo=bar" * "ip1,ip2,...#foo=bar"
*/ */
static int static int
dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
{ {
struct user_key_payload *upayload; struct user_key_payload *upayload;
unsigned long derrno; unsigned long derrno;
int ret; int ret;
size_t result_len = 0; size_t datalen = prep->datalen, result_len = 0;
const char *data = _data, *end, *opt; const char *data = prep->data, *end, *opt;
kenter("%%%d,%s,'%*.*s',%zu", kenter("%%%d,%s,'%*.*s',%zu",
key->serial, key->description, key->serial, key->description,
...@@ -259,19 +259,15 @@ static int __init init_dns_resolver(void) ...@@ -259,19 +259,15 @@ static int __init init_dns_resolver(void)
if (!cred) if (!cred)
return -ENOMEM; return -ENOMEM;
keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred, keyring = keyring_alloc(".dns_resolver", 0, 0, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ, KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA); KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto failed_put_cred; goto failed_put_cred;
} }
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
if (ret < 0)
goto failed_put_key;
ret = register_key_type(&key_type_dns_resolver); ret = register_key_type(&key_type_dns_resolver);
if (ret < 0) if (ret < 0)
goto failed_put_key; goto failed_put_key;
...@@ -303,3 +299,4 @@ static void __exit exit_dns_resolver(void) ...@@ -303,3 +299,4 @@ static void __exit exit_dns_resolver(void)
module_init(init_dns_resolver) module_init(init_dns_resolver)
module_exit(exit_dns_resolver) module_exit(exit_dns_resolver)
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#include "ar-internal.h" #include "ar-internal.h"
static int rxrpc_vet_description_s(const char *); static int rxrpc_vet_description_s(const char *);
static int rxrpc_instantiate(struct key *, const void *, size_t); static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *);
static int rxrpc_instantiate_s(struct key *, const void *, size_t); static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);
static void rxrpc_destroy(struct key *); static void rxrpc_destroy(struct key *);
static void rxrpc_destroy_s(struct key *); static void rxrpc_destroy_s(struct key *);
static void rxrpc_describe(const struct key *, struct seq_file *); static void rxrpc_describe(const struct key *, struct seq_file *);
...@@ -678,7 +678,7 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal ...@@ -678,7 +678,7 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal
* *
* if no data is provided, then a no-security key is made * if no data is provided, then a no-security key is made
*/ */
static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep)
{ {
const struct rxrpc_key_data_v1 *v1; const struct rxrpc_key_data_v1 *v1;
struct rxrpc_key_token *token, **pp; struct rxrpc_key_token *token, **pp;
...@@ -686,26 +686,26 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) ...@@ -686,26 +686,26 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
u32 kver; u32 kver;
int ret; int ret;
_enter("{%x},,%zu", key_serial(key), datalen); _enter("{%x},,%zu", key_serial(key), prep->datalen);
/* handle a no-security key */ /* handle a no-security key */
if (!data && datalen == 0) if (!prep->data && prep->datalen == 0)
return 0; return 0;
/* determine if the XDR payload format is being used */ /* determine if the XDR payload format is being used */
if (datalen > 7 * 4) { if (prep->datalen > 7 * 4) {
ret = rxrpc_instantiate_xdr(key, data, datalen); ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);
if (ret != -EPROTO) if (ret != -EPROTO)
return ret; return ret;
} }
/* get the key interface version number */ /* get the key interface version number */
ret = -EINVAL; ret = -EINVAL;
if (datalen <= 4 || !data) if (prep->datalen <= 4 || !prep->data)
goto error; goto error;
memcpy(&kver, data, sizeof(kver)); memcpy(&kver, prep->data, sizeof(kver));
data += sizeof(kver); prep->data += sizeof(kver);
datalen -= sizeof(kver); prep->datalen -= sizeof(kver);
_debug("KEY I/F VERSION: %u", kver); _debug("KEY I/F VERSION: %u", kver);
...@@ -715,11 +715,11 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) ...@@ -715,11 +715,11 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
/* deal with a version 1 key */ /* deal with a version 1 key */
ret = -EINVAL; ret = -EINVAL;
if (datalen < sizeof(*v1)) if (prep->datalen < sizeof(*v1))
goto error; goto error;
v1 = data; v1 = prep->data;
if (datalen != sizeof(*v1) + v1->ticket_length) if (prep->datalen != sizeof(*v1) + v1->ticket_length)
goto error; goto error;
_debug("SCIX: %u", v1->security_index); _debug("SCIX: %u", v1->security_index);
...@@ -784,17 +784,17 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) ...@@ -784,17 +784,17 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
* instantiate a server secret key * instantiate a server secret key
* data should be a pointer to the 8-byte secret key * data should be a pointer to the 8-byte secret key
*/ */
static int rxrpc_instantiate_s(struct key *key, const void *data, static int rxrpc_instantiate_s(struct key *key,
size_t datalen) struct key_preparsed_payload *prep)
{ {
struct crypto_blkcipher *ci; struct crypto_blkcipher *ci;
_enter("{%x},,%zu", key_serial(key), datalen); _enter("{%x},,%zu", key_serial(key), prep->datalen);
if (datalen != 8) if (prep->datalen != 8)
return -EINVAL; return -EINVAL;
memcpy(&key->type_data, data, 8); memcpy(&key->type_data, prep->data, 8);
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(ci)) { if (IS_ERR(ci)) {
...@@ -802,7 +802,7 @@ static int rxrpc_instantiate_s(struct key *key, const void *data, ...@@ -802,7 +802,7 @@ static int rxrpc_instantiate_s(struct key *key, const void *data,
return PTR_ERR(ci); return PTR_ERR(ci);
} }
if (crypto_blkcipher_setkey(ci, data, 8) < 0) if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
BUG(); BUG();
key->payload.data = ci; key->payload.data = ci;
......
...@@ -773,8 +773,8 @@ static int encrypted_init(struct encrypted_key_payload *epayload, ...@@ -773,8 +773,8 @@ static int encrypted_init(struct encrypted_key_payload *epayload,
* *
* On success, return 0. Otherwise return errno. * On success, return 0. Otherwise return errno.
*/ */
static int encrypted_instantiate(struct key *key, const void *data, static int encrypted_instantiate(struct key *key,
size_t datalen) struct key_preparsed_payload *prep)
{ {
struct encrypted_key_payload *epayload = NULL; struct encrypted_key_payload *epayload = NULL;
char *datablob = NULL; char *datablob = NULL;
...@@ -782,16 +782,17 @@ static int encrypted_instantiate(struct key *key, const void *data, ...@@ -782,16 +782,17 @@ static int encrypted_instantiate(struct key *key, const void *data,
char *master_desc = NULL; char *master_desc = NULL;
char *decrypted_datalen = NULL; char *decrypted_datalen = NULL;
char *hex_encoded_iv = NULL; char *hex_encoded_iv = NULL;
size_t datalen = prep->datalen;
int ret; int ret;
if (datalen <= 0 || datalen > 32767 || !data) if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL; return -EINVAL;
datablob = kmalloc(datalen + 1, GFP_KERNEL); datablob = kmalloc(datalen + 1, GFP_KERNEL);
if (!datablob) if (!datablob)
return -ENOMEM; return -ENOMEM;
datablob[datalen] = 0; datablob[datalen] = 0;
memcpy(datablob, data, datalen); memcpy(datablob, prep->data, datalen);
ret = datablob_parse(datablob, &format, &master_desc, ret = datablob_parse(datablob, &format, &master_desc,
&decrypted_datalen, &hex_encoded_iv); &decrypted_datalen, &hex_encoded_iv);
if (ret < 0) if (ret < 0)
...@@ -834,16 +835,17 @@ static void encrypted_rcu_free(struct rcu_head *rcu) ...@@ -834,16 +835,17 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
* *
* On success, return 0. Otherwise return errno. * On success, return 0. Otherwise return errno.
*/ */
static int encrypted_update(struct key *key, const void *data, size_t datalen) static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
{ {
struct encrypted_key_payload *epayload = key->payload.data; struct encrypted_key_payload *epayload = key->payload.data;
struct encrypted_key_payload *new_epayload; struct encrypted_key_payload *new_epayload;
char *buf; char *buf;
char *new_master_desc = NULL; char *new_master_desc = NULL;
const char *format = NULL; const char *format = NULL;
size_t datalen = prep->datalen;
int ret = 0; int ret = 0;
if (datalen <= 0 || datalen > 32767 || !data) if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL; return -EINVAL;
buf = kmalloc(datalen + 1, GFP_KERNEL); buf = kmalloc(datalen + 1, GFP_KERNEL);
...@@ -851,7 +853,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) ...@@ -851,7 +853,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
return -ENOMEM; return -ENOMEM;
buf[datalen] = 0; buf[datalen] = 0;
memcpy(buf, data, datalen); memcpy(buf, prep->data, datalen);
ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL); ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
if (ret < 0) if (ret < 0)
goto out; goto out;
......
...@@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve); ...@@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve);
* key_construction_mutex. * key_construction_mutex.
*/ */
static int __key_instantiate_and_link(struct key *key, static int __key_instantiate_and_link(struct key *key,
const void *data, struct key_preparsed_payload *prep,
size_t datalen,
struct key *keyring, struct key *keyring,
struct key *authkey, struct key *authkey,
unsigned long *_prealloc) unsigned long *_prealloc)
...@@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key, ...@@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key,
/* can't instantiate twice */ /* can't instantiate twice */
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
/* instantiate the key */ /* instantiate the key */
ret = key->type->instantiate(key, data, datalen); ret = key->type->instantiate(key, prep);
if (ret == 0) { if (ret == 0) {
/* mark the key as being instantiated */ /* mark the key as being instantiated */
...@@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key, ...@@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key,
struct key *keyring, struct key *keyring,
struct key *authkey) struct key *authkey)
{ {
struct key_preparsed_payload prep;
unsigned long prealloc; unsigned long prealloc;
int ret; int ret;
memset(&prep, 0, sizeof(prep));
prep.data = data;
prep.datalen = datalen;
prep.quotalen = key->type->def_datalen;
if (key->type->preparse) {
ret = key->type->preparse(&prep);
if (ret < 0)
goto error;
}
if (keyring) { if (keyring) {
ret = __key_link_begin(keyring, key->type, key->description, ret = __key_link_begin(keyring, key->type, key->description,
&prealloc); &prealloc);
if (ret < 0) if (ret < 0)
return ret; goto error_free_preparse;
} }
ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey, ret = __key_instantiate_and_link(key, &prep, keyring, authkey,
&prealloc); &prealloc);
if (keyring) if (keyring)
__key_link_end(keyring, key->type, prealloc); __key_link_end(keyring, key->type, prealloc);
error_free_preparse:
if (key->type->preparse)
key->type->free_preparse(&prep);
error:
return ret; return ret;
} }
...@@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype) ...@@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype)
* if we get an error. * if we get an error.
*/ */
static inline key_ref_t __key_update(key_ref_t key_ref, static inline key_ref_t __key_update(key_ref_t key_ref,
const void *payload, size_t plen) struct key_preparsed_payload *prep)
{ {
struct key *key = key_ref_to_ptr(key_ref); struct key *key = key_ref_to_ptr(key_ref);
int ret; int ret;
...@@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref, ...@@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
down_write(&key->sem); down_write(&key->sem);
ret = key->type->update(key, payload, plen); ret = key->type->update(key, prep);
if (ret == 0) if (ret == 0)
/* updating a negative key instantiates it */ /* updating a negative key instantiates it */
clear_bit(KEY_FLAG_NEGATIVE, &key->flags); clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
...@@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
unsigned long flags) unsigned long flags)
{ {
unsigned long prealloc; unsigned long prealloc;
struct key_preparsed_payload prep;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct key_type *ktype; struct key_type *ktype;
struct key *keyring, *key = NULL; struct key *keyring, *key = NULL;
...@@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
} }
key_ref = ERR_PTR(-EINVAL); key_ref = ERR_PTR(-EINVAL);
if (!ktype->match || !ktype->instantiate) if (!ktype->match || !ktype->instantiate ||
goto error_2; (!description && !ktype->preparse))
goto error_put_type;
keyring = key_ref_to_ptr(keyring_ref); keyring = key_ref_to_ptr(keyring_ref);
...@@ -798,18 +814,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -798,18 +814,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_ref = ERR_PTR(-ENOTDIR); key_ref = ERR_PTR(-ENOTDIR);
if (keyring->type != &key_type_keyring) if (keyring->type != &key_type_keyring)
goto error_2; goto error_put_type;
memset(&prep, 0, sizeof(prep));
prep.data = payload;
prep.datalen = plen;
prep.quotalen = ktype->def_datalen;
if (ktype->preparse) {
ret = ktype->preparse(&prep);
if (ret < 0) {
key_ref = ERR_PTR(ret);
goto error_put_type;
}
if (!description)
description = prep.description;
key_ref = ERR_PTR(-EINVAL);
if (!description)
goto error_free_prep;
}
ret = __key_link_begin(keyring, ktype, description, &prealloc); ret = __key_link_begin(keyring, ktype, description, &prealloc);
if (ret < 0) if (ret < 0) {
goto error_2; key_ref = ERR_PTR(ret);
goto error_free_prep;
}
/* if we're going to allocate a new key, we're going to have /* if we're going to allocate a new key, we're going to have
* to modify the keyring */ * to modify the keyring */
ret = key_permission(keyring_ref, KEY_WRITE); ret = key_permission(keyring_ref, KEY_WRITE);
if (ret < 0) { if (ret < 0) {
key_ref = ERR_PTR(ret); key_ref = ERR_PTR(ret);
goto error_3; goto error_link_end;
} }
/* if it's possible to update this type of key, search for an existing /* if it's possible to update this type of key, search for an existing
...@@ -826,13 +861,13 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -826,13 +861,13 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* if the client doesn't provide, decide on the permissions we want */ /* if the client doesn't provide, decide on the permissions we want */
if (perm == KEY_PERM_UNDEF) { if (perm == KEY_PERM_UNDEF) {
perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR; perm |= KEY_USR_VIEW;
if (ktype->read) if (ktype->read)
perm |= KEY_POS_READ | KEY_USR_READ; perm |= KEY_POS_READ;
if (ktype == &key_type_keyring || ktype->update) if (ktype == &key_type_keyring || ktype->update)
perm |= KEY_USR_WRITE; perm |= KEY_POS_WRITE;
} }
/* allocate a new key */ /* allocate a new key */
...@@ -840,25 +875,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -840,25 +875,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
perm, flags); perm, flags);
if (IS_ERR(key)) { if (IS_ERR(key)) {
key_ref = ERR_CAST(key); key_ref = ERR_CAST(key);
goto error_3; goto error_link_end;
} }
/* instantiate it and link it into the target keyring */ /* instantiate it and link it into the target keyring */
ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL, ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc);
&prealloc);
if (ret < 0) { if (ret < 0) {
key_put(key); key_put(key);
key_ref = ERR_PTR(ret); key_ref = ERR_PTR(ret);
goto error_3; goto error_link_end;
} }
key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
error_3: error_link_end:
__key_link_end(keyring, ktype, prealloc); __key_link_end(keyring, ktype, prealloc);
error_2: error_free_prep:
if (ktype->preparse)
ktype->free_preparse(&prep);
error_put_type:
key_type_put(ktype); key_type_put(ktype);
error: error:
return key_ref; return key_ref;
found_matching_key: found_matching_key:
...@@ -866,10 +903,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -866,10 +903,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
* - we can drop the locks first as we have the key pinned * - we can drop the locks first as we have the key pinned
*/ */
__key_link_end(keyring, ktype, prealloc); __key_link_end(keyring, ktype, prealloc);
key_type_put(ktype);
key_ref = __key_update(key_ref, payload, plen); key_ref = __key_update(key_ref, &prep);
goto error; goto error_free_prep;
} }
EXPORT_SYMBOL(key_create_or_update); EXPORT_SYMBOL(key_create_or_update);
...@@ -888,6 +924,7 @@ EXPORT_SYMBOL(key_create_or_update); ...@@ -888,6 +924,7 @@ EXPORT_SYMBOL(key_create_or_update);
*/ */
int key_update(key_ref_t key_ref, const void *payload, size_t plen) int key_update(key_ref_t key_ref, const void *payload, size_t plen)
{ {
struct key_preparsed_payload prep;
struct key *key = key_ref_to_ptr(key_ref); struct key *key = key_ref_to_ptr(key_ref);
int ret; int ret;
...@@ -900,18 +937,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) ...@@ -900,18 +937,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
/* attempt to update it if supported */ /* attempt to update it if supported */
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
if (key->type->update) { if (!key->type->update)
down_write(&key->sem); goto error;
ret = key->type->update(key, payload, plen);
if (ret == 0)
/* updating a negative key instantiates it */
clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
up_write(&key->sem); memset(&prep, 0, sizeof(prep));
prep.data = payload;
prep.datalen = plen;
prep.quotalen = key->type->def_datalen;
if (key->type->preparse) {
ret = key->type->preparse(&prep);
if (ret < 0)
goto error;
} }
error: down_write(&key->sem);
ret = key->type->update(key, &prep);
if (ret == 0)
/* updating a negative key instantiates it */
clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
up_write(&key->sem);
if (key->type->preparse)
key->type->free_preparse(&prep);
error:
return ret; return ret;
} }
EXPORT_SYMBOL(key_update); EXPORT_SYMBOL(key_update);
......
...@@ -46,6 +46,9 @@ static int key_get_type_from_user(char *type, ...@@ -46,6 +46,9 @@ static int key_get_type_from_user(char *type,
* Extract the description of a new key from userspace and either add it as a * Extract the description of a new key from userspace and either add it as a
* new key to the specified keyring or update a matching key in that keyring. * new key to the specified keyring or update a matching key in that keyring.
* *
* If the description is NULL or an empty string, the key type is asked to
* generate one from the payload.
*
* The keyring must be writable so that we can attach the key to it. * The keyring must be writable so that we can attach the key to it.
* *
* If successful, the new key's serial number is returned, otherwise an error * If successful, the new key's serial number is returned, otherwise an error
...@@ -72,10 +75,17 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, ...@@ -72,10 +75,17 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
if (ret < 0) if (ret < 0)
goto error; goto error;
description = strndup_user(_description, PAGE_SIZE); description = NULL;
if (IS_ERR(description)) { if (_description) {
ret = PTR_ERR(description); description = strndup_user(_description, PAGE_SIZE);
goto error; if (IS_ERR(description)) {
ret = PTR_ERR(description);
goto error;
}
if (!*description) {
kfree(description);
description = NULL;
}
} }
/* pull the payload in if one was supplied */ /* pull the payload in if one was supplied */
...@@ -1112,12 +1122,12 @@ long keyctl_instantiate_key_iov(key_serial_t id, ...@@ -1112,12 +1122,12 @@ long keyctl_instantiate_key_iov(key_serial_t id,
ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
ARRAY_SIZE(iovstack), iovstack, &iov); ARRAY_SIZE(iovstack), iovstack, &iov);
if (ret < 0) if (ret < 0)
return ret; goto err;
if (ret == 0) if (ret == 0)
goto no_payload_free; goto no_payload_free;
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
err:
if (iov != iovstack) if (iov != iovstack)
kfree(iov); kfree(iov);
return ret; return ret;
...@@ -1475,7 +1485,8 @@ long keyctl_session_to_parent(void) ...@@ -1475,7 +1485,8 @@ long keyctl_session_to_parent(void)
goto error_keyring; goto error_keyring;
newwork = &cred->rcu; newwork = &cred->rcu;
cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); cred->session_keyring = key_ref_to_ptr(keyring_r);
keyring_r = NULL;
init_task_work(newwork, key_change_session_keyring); init_task_work(newwork, key_change_session_keyring);
me = current; me = current;
...@@ -1500,7 +1511,7 @@ long keyctl_session_to_parent(void) ...@@ -1500,7 +1511,7 @@ long keyctl_session_to_parent(void)
mycred = current_cred(); mycred = current_cred();
pcred = __task_cred(parent); pcred = __task_cred(parent);
if (mycred == pcred || if (mycred == pcred ||
mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) { mycred->session_keyring == pcred->session_keyring) {
ret = 0; ret = 0;
goto unlock; goto unlock;
} }
...@@ -1516,9 +1527,9 @@ long keyctl_session_to_parent(void) ...@@ -1516,9 +1527,9 @@ long keyctl_session_to_parent(void)
goto unlock; goto unlock;
/* the keyrings must have the same UID */ /* the keyrings must have the same UID */
if ((pcred->tgcred->session_keyring && if ((pcred->session_keyring &&
pcred->tgcred->session_keyring->uid != mycred->euid) || pcred->session_keyring->uid != mycred->euid) ||
mycred->tgcred->session_keyring->uid != mycred->euid) mycred->session_keyring->uid != mycred->euid)
goto unlock; goto unlock;
/* cancel an already pending keyring replacement */ /* cancel an already pending keyring replacement */
......
...@@ -66,7 +66,7 @@ static inline unsigned keyring_hash(const char *desc) ...@@ -66,7 +66,7 @@ static inline unsigned keyring_hash(const char *desc)
* operations. * operations.
*/ */
static int keyring_instantiate(struct key *keyring, static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen); struct key_preparsed_payload *prep);
static int keyring_match(const struct key *keyring, const void *criterion); static int keyring_match(const struct key *keyring, const void *criterion);
static void keyring_revoke(struct key *keyring); static void keyring_revoke(struct key *keyring);
static void keyring_destroy(struct key *keyring); static void keyring_destroy(struct key *keyring);
...@@ -121,12 +121,12 @@ static void keyring_publish_name(struct key *keyring) ...@@ -121,12 +121,12 @@ static void keyring_publish_name(struct key *keyring)
* Returns 0 on success, -EINVAL if given any data. * Returns 0 on success, -EINVAL if given any data.
*/ */
static int keyring_instantiate(struct key *keyring, static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen) struct key_preparsed_payload *prep)
{ {
int ret; int ret;
ret = -EINVAL; ret = -EINVAL;
if (datalen == 0) { if (prep->datalen == 0) {
/* make the keyring available by name if it has one */ /* make the keyring available by name if it has one */
keyring_publish_name(keyring); keyring_publish_name(keyring);
ret = 0; ret = 0;
...@@ -257,17 +257,14 @@ static long keyring_read(const struct key *keyring, ...@@ -257,17 +257,14 @@ static long keyring_read(const struct key *keyring,
* Allocate a keyring and link into the destination keyring. * Allocate a keyring and link into the destination keyring.
*/ */
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred, unsigned long flags, const struct cred *cred, key_perm_t perm,
struct key *dest) unsigned long flags, struct key *dest)
{ {
struct key *keyring; struct key *keyring;
int ret; int ret;
keyring = key_alloc(&key_type_keyring, description, keyring = key_alloc(&key_type_keyring, description,
uid, gid, cred, uid, gid, cred, perm, flags);
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
flags);
if (!IS_ERR(keyring)) { if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
if (ret < 0) { if (ret < 0) {
...@@ -278,6 +275,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, ...@@ -278,6 +275,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
return keyring; return keyring;
} }
EXPORT_SYMBOL(keyring_alloc);
/** /**
* keyring_search_aux - Search a keyring tree for a key matching some criteria * keyring_search_aux - Search a keyring tree for a key matching some criteria
......
...@@ -46,9 +46,11 @@ int install_user_keyrings(void) ...@@ -46,9 +46,11 @@ int install_user_keyrings(void)
struct user_struct *user; struct user_struct *user;
const struct cred *cred; const struct cred *cred;
struct key *uid_keyring, *session_keyring; struct key *uid_keyring, *session_keyring;
key_perm_t user_keyring_perm;
char buf[20]; char buf[20];
int ret; int ret;
user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL;
cred = current_cred(); cred = current_cred();
user = cred->user; user = cred->user;
...@@ -72,8 +74,8 @@ int install_user_keyrings(void) ...@@ -72,8 +74,8 @@ int install_user_keyrings(void)
uid_keyring = find_keyring_by_name(buf, true); uid_keyring = find_keyring_by_name(buf, true);
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
cred, KEY_ALLOC_IN_QUOTA, cred, user_keyring_perm,
NULL); KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
ret = PTR_ERR(uid_keyring); ret = PTR_ERR(uid_keyring);
goto error; goto error;
...@@ -88,7 +90,8 @@ int install_user_keyrings(void) ...@@ -88,7 +90,8 @@ int install_user_keyrings(void)
if (IS_ERR(session_keyring)) { if (IS_ERR(session_keyring)) {
session_keyring = session_keyring =
keyring_alloc(buf, user->uid, (gid_t) -1, keyring_alloc(buf, user->uid, (gid_t) -1,
cred, KEY_ALLOC_IN_QUOTA, NULL); cred, user_keyring_perm,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(session_keyring)) { if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring); ret = PTR_ERR(session_keyring);
goto error_release; goto error_release;
...@@ -129,6 +132,7 @@ int install_thread_keyring_to_cred(struct cred *new) ...@@ -129,6 +132,7 @@ int install_thread_keyring_to_cred(struct cred *new)
struct key *keyring; struct key *keyring;
keyring = keyring_alloc("_tid", new->uid, new->gid, new, keyring = keyring_alloc("_tid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN, NULL); KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) if (IS_ERR(keyring))
return PTR_ERR(keyring); return PTR_ERR(keyring);
...@@ -169,27 +173,18 @@ static int install_thread_keyring(void) ...@@ -169,27 +173,18 @@ static int install_thread_keyring(void)
int install_process_keyring_to_cred(struct cred *new) int install_process_keyring_to_cred(struct cred *new)
{ {
struct key *keyring; struct key *keyring;
int ret;
if (new->tgcred->process_keyring) if (new->process_keyring)
return -EEXIST; return -EEXIST;
keyring = keyring_alloc("_pid", new->uid, new->gid, keyring = keyring_alloc("_pid", new->uid, new->gid, new,
new, KEY_ALLOC_QUOTA_OVERRUN, NULL); KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) if (IS_ERR(keyring))
return PTR_ERR(keyring); return PTR_ERR(keyring);
spin_lock_irq(&new->tgcred->lock); new->process_keyring = keyring;
if (!new->tgcred->process_keyring) { return 0;
new->tgcred->process_keyring = keyring;
keyring = NULL;
ret = 0;
} else {
ret = -EEXIST;
}
spin_unlock_irq(&new->tgcred->lock);
key_put(keyring);
return ret;
} }
/* /*
...@@ -230,11 +225,12 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) ...@@ -230,11 +225,12 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
/* create an empty session keyring */ /* create an empty session keyring */
if (!keyring) { if (!keyring) {
flags = KEY_ALLOC_QUOTA_OVERRUN; flags = KEY_ALLOC_QUOTA_OVERRUN;
if (cred->tgcred->session_keyring) if (cred->session_keyring)
flags = KEY_ALLOC_IN_QUOTA; flags = KEY_ALLOC_IN_QUOTA;
keyring = keyring_alloc("_ses", cred->uid, cred->gid, keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
cred, flags, NULL); KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
flags, NULL);
if (IS_ERR(keyring)) if (IS_ERR(keyring))
return PTR_ERR(keyring); return PTR_ERR(keyring);
} else { } else {
...@@ -242,17 +238,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) ...@@ -242,17 +238,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
} }
/* install the keyring */ /* install the keyring */
spin_lock_irq(&cred->tgcred->lock); old = cred->session_keyring;
old = cred->tgcred->session_keyring; rcu_assign_pointer(cred->session_keyring, keyring);
rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
spin_unlock_irq(&cred->tgcred->lock); if (old)
/* we're using RCU on the pointer, but there's no point synchronising
* on it if it didn't previously point to anything */
if (old) {
synchronize_rcu();
key_put(old); key_put(old);
}
return 0; return 0;
} }
...@@ -357,8 +347,6 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -357,8 +347,6 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
switch (PTR_ERR(key_ref)) { switch (PTR_ERR(key_ref)) {
case -EAGAIN: /* no key */ case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */ case -ENOKEY: /* negative key */
ret = key_ref; ret = key_ref;
break; break;
...@@ -369,9 +357,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -369,9 +357,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
} }
/* search the process keyring second */ /* search the process keyring second */
if (cred->tgcred->process_keyring) { if (cred->process_keyring) {
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(cred->tgcred->process_keyring, 1), make_key_ref(cred->process_keyring, 1),
cred, type, description, match, no_state_check); cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
...@@ -390,12 +378,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -390,12 +378,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
} }
/* search the session keyring */ /* search the session keyring */
if (cred->tgcred->session_keyring) { if (cred->session_keyring) {
rcu_read_lock(); rcu_read_lock();
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(rcu_dereference( make_key_ref(rcu_dereference(cred->session_keyring), 1),
cred->tgcred->session_keyring),
1),
cred, type, description, match, no_state_check); cred, type, description, match, no_state_check);
rcu_read_unlock(); rcu_read_unlock();
...@@ -565,7 +551,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -565,7 +551,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
break; break;
case KEY_SPEC_PROCESS_KEYRING: case KEY_SPEC_PROCESS_KEYRING:
if (!cred->tgcred->process_keyring) { if (!cred->process_keyring) {
if (!(lflags & KEY_LOOKUP_CREATE)) if (!(lflags & KEY_LOOKUP_CREATE))
goto error; goto error;
...@@ -577,13 +563,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -577,13 +563,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
goto reget_creds; goto reget_creds;
} }
key = cred->tgcred->process_keyring; key = cred->process_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_SESSION_KEYRING: case KEY_SPEC_SESSION_KEYRING:
if (!cred->tgcred->session_keyring) { if (!cred->session_keyring) {
/* always install a session keyring upon access if one /* always install a session keyring upon access if one
* doesn't exist yet */ * doesn't exist yet */
ret = install_user_keyrings(); ret = install_user_keyrings();
...@@ -598,7 +584,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -598,7 +584,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
if (ret < 0) if (ret < 0)
goto error; goto error;
goto reget_creds; goto reget_creds;
} else if (cred->tgcred->session_keyring == } else if (cred->session_keyring ==
cred->user->session_keyring && cred->user->session_keyring &&
lflags & KEY_LOOKUP_CREATE) { lflags & KEY_LOOKUP_CREATE) {
ret = join_session_keyring(NULL); ret = join_session_keyring(NULL);
...@@ -608,7 +594,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -608,7 +594,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
} }
rcu_read_lock(); rcu_read_lock();
key = rcu_dereference(cred->tgcred->session_keyring); key = rcu_dereference(cred->session_keyring);
atomic_inc(&key->usage); atomic_inc(&key->usage);
rcu_read_unlock(); rcu_read_unlock();
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
...@@ -768,12 +754,6 @@ long join_session_keyring(const char *name) ...@@ -768,12 +754,6 @@ long join_session_keyring(const char *name)
struct key *keyring; struct key *keyring;
long ret, serial; long ret, serial;
/* only permit this if there's a single thread in the thread group -
* this avoids us having to adjust the creds on all threads and risking
* ENOMEM */
if (!current_is_single_threaded())
return -EMLINK;
new = prepare_creds(); new = prepare_creds();
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
...@@ -785,7 +765,7 @@ long join_session_keyring(const char *name) ...@@ -785,7 +765,7 @@ long join_session_keyring(const char *name)
if (ret < 0) if (ret < 0)
goto error; goto error;
serial = new->tgcred->session_keyring->serial; serial = new->session_keyring->serial;
ret = commit_creds(new); ret = commit_creds(new);
if (ret == 0) if (ret == 0)
ret = serial; ret = serial;
...@@ -799,8 +779,10 @@ long join_session_keyring(const char *name) ...@@ -799,8 +779,10 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, false); keyring = find_keyring_by_name(name, false);
if (PTR_ERR(keyring) == -ENOKEY) { if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */ /* not found - try and create a new one */
keyring = keyring_alloc(name, old->uid, old->gid, old, keyring = keyring_alloc(
KEY_ALLOC_IN_QUOTA, NULL); name, old->uid, old->gid, old,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error2; goto error2;
...@@ -808,6 +790,9 @@ long join_session_keyring(const char *name) ...@@ -808,6 +790,9 @@ long join_session_keyring(const char *name)
} else if (IS_ERR(keyring)) { } else if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error2; goto error2;
} else if (keyring == new->session_keyring) {
ret = 0;
goto error2;
} }
/* we've got a keyring - now to install it */ /* we've got a keyring - now to install it */
...@@ -864,8 +849,7 @@ void key_change_session_keyring(struct callback_head *twork) ...@@ -864,8 +849,7 @@ void key_change_session_keyring(struct callback_head *twork)
new->jit_keyring = old->jit_keyring; new->jit_keyring = old->jit_keyring;
new->thread_keyring = key_get(old->thread_keyring); new->thread_keyring = key_get(old->thread_keyring);
new->tgcred->tgid = old->tgcred->tgid; new->process_keyring = key_get(old->process_keyring);
new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
security_transfer_creds(new, old); security_transfer_creds(new, old);
......
...@@ -126,6 +126,7 @@ static int call_sbin_request_key(struct key_construction *cons, ...@@ -126,6 +126,7 @@ static int call_sbin_request_key(struct key_construction *cons,
cred = get_current_cred(); cred = get_current_cred();
keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_QUOTA_OVERRUN, NULL); KEY_ALLOC_QUOTA_OVERRUN, NULL);
put_cred(cred); put_cred(cred);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
...@@ -150,12 +151,12 @@ static int call_sbin_request_key(struct key_construction *cons, ...@@ -150,12 +151,12 @@ static int call_sbin_request_key(struct key_construction *cons,
cred->thread_keyring ? cred->thread_keyring->serial : 0); cred->thread_keyring ? cred->thread_keyring->serial : 0);
prkey = 0; prkey = 0;
if (cred->tgcred->process_keyring) if (cred->process_keyring)
prkey = cred->tgcred->process_keyring->serial; prkey = cred->process_keyring->serial;
sprintf(keyring_str[1], "%d", prkey); sprintf(keyring_str[1], "%d", prkey);
rcu_read_lock(); rcu_read_lock();
session = rcu_dereference(cred->tgcred->session_keyring); session = rcu_dereference(cred->session_keyring);
if (!session) if (!session)
session = cred->user->session_keyring; session = cred->user->session_keyring;
sskey = session->serial; sskey = session->serial;
...@@ -297,14 +298,14 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) ...@@ -297,14 +298,14 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
break; break;
case KEY_REQKEY_DEFL_PROCESS_KEYRING: case KEY_REQKEY_DEFL_PROCESS_KEYRING:
dest_keyring = key_get(cred->tgcred->process_keyring); dest_keyring = key_get(cred->process_keyring);
if (dest_keyring) if (dest_keyring)
break; break;
case KEY_REQKEY_DEFL_SESSION_KEYRING: case KEY_REQKEY_DEFL_SESSION_KEYRING:
rcu_read_lock(); rcu_read_lock();
dest_keyring = key_get( dest_keyring = key_get(
rcu_dereference(cred->tgcred->session_keyring)); rcu_dereference(cred->session_keyring));
rcu_read_unlock(); rcu_read_unlock();
if (dest_keyring) if (dest_keyring)
...@@ -347,6 +348,7 @@ static int construct_alloc_key(struct key_type *type, ...@@ -347,6 +348,7 @@ static int construct_alloc_key(struct key_type *type,
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
unsigned long prealloc; unsigned long prealloc;
struct key *key; struct key *key;
key_perm_t perm;
key_ref_t key_ref; key_ref_t key_ref;
int ret; int ret;
...@@ -355,8 +357,15 @@ static int construct_alloc_key(struct key_type *type, ...@@ -355,8 +357,15 @@ static int construct_alloc_key(struct key_type *type,
*_key = NULL; *_key = NULL;
mutex_lock(&user->cons_lock); mutex_lock(&user->cons_lock);
perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
perm |= KEY_USR_VIEW;
if (type->read)
perm |= KEY_POS_READ;
if (type == &key_type_keyring || type->update)
perm |= KEY_POS_WRITE;
key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
KEY_POS_ALL, flags); perm, flags);
if (IS_ERR(key)) if (IS_ERR(key))
goto alloc_failed; goto alloc_failed;
......
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "internal.h" #include "internal.h"
static int request_key_auth_instantiate(struct key *, const void *, size_t); 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_describe(const struct key *, struct seq_file *);
static void request_key_auth_revoke(struct key *); static void request_key_auth_revoke(struct key *);
static void request_key_auth_destroy(struct key *); static void request_key_auth_destroy(struct key *);
...@@ -42,10 +43,9 @@ struct key_type key_type_request_key_auth = { ...@@ -42,10 +43,9 @@ struct key_type key_type_request_key_auth = {
* Instantiate a request-key authorisation key. * Instantiate a request-key authorisation key.
*/ */
static int request_key_auth_instantiate(struct key *key, static int request_key_auth_instantiate(struct key *key,
const void *data, struct key_preparsed_payload *prep)
size_t datalen)
{ {
key->payload.data = (struct request_key_auth *) data; key->payload.data = (struct request_key_auth *)prep->data;
return 0; return 0;
} }
......
...@@ -895,23 +895,24 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key) ...@@ -895,23 +895,24 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
* *
* On success, return 0. Otherwise return errno. * On success, return 0. Otherwise return errno.
*/ */
static int trusted_instantiate(struct key *key, const void *data, static int trusted_instantiate(struct key *key,
size_t datalen) struct key_preparsed_payload *prep)
{ {
struct trusted_key_payload *payload = NULL; struct trusted_key_payload *payload = NULL;
struct trusted_key_options *options = NULL; struct trusted_key_options *options = NULL;
size_t datalen = prep->datalen;
char *datablob; char *datablob;
int ret = 0; int ret = 0;
int key_cmd; int key_cmd;
size_t key_len; size_t key_len;
if (datalen <= 0 || datalen > 32767 || !data) if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL; return -EINVAL;
datablob = kmalloc(datalen + 1, GFP_KERNEL); datablob = kmalloc(datalen + 1, GFP_KERNEL);
if (!datablob) if (!datablob)
return -ENOMEM; return -ENOMEM;
memcpy(datablob, data, datalen); memcpy(datablob, prep->data, datalen);
datablob[datalen] = '\0'; datablob[datalen] = '\0';
options = trusted_options_alloc(); options = trusted_options_alloc();
...@@ -981,17 +982,18 @@ static void trusted_rcu_free(struct rcu_head *rcu) ...@@ -981,17 +982,18 @@ static void trusted_rcu_free(struct rcu_head *rcu)
/* /*
* trusted_update - reseal an existing key with new PCR values * trusted_update - reseal an existing key with new PCR values
*/ */
static int trusted_update(struct key *key, const void *data, size_t datalen) static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
{ {
struct trusted_key_payload *p = key->payload.data; struct trusted_key_payload *p = key->payload.data;
struct trusted_key_payload *new_p; struct trusted_key_payload *new_p;
struct trusted_key_options *new_o; struct trusted_key_options *new_o;
size_t datalen = prep->datalen;
char *datablob; char *datablob;
int ret = 0; int ret = 0;
if (!p->migratable) if (!p->migratable)
return -EPERM; return -EPERM;
if (datalen <= 0 || datalen > 32767 || !data) if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL; return -EINVAL;
datablob = kmalloc(datalen + 1, GFP_KERNEL); datablob = kmalloc(datalen + 1, GFP_KERNEL);
...@@ -1008,7 +1010,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen) ...@@ -1008,7 +1010,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
goto out; goto out;
} }
memcpy(datablob, data, datalen); memcpy(datablob, prep->data, datalen);
datablob[datalen] = '\0'; datablob[datalen] = '\0';
ret = datablob_parse(datablob, new_p, new_o); ret = datablob_parse(datablob, new_p, new_o);
if (ret != Opt_update) { if (ret != Opt_update) {
......
...@@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon); ...@@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon);
/* /*
* instantiate a user defined key * instantiate a user defined key
*/ */
int user_instantiate(struct key *key, const void *data, size_t datalen) int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
{ {
struct user_key_payload *upayload; struct user_key_payload *upayload;
size_t datalen = prep->datalen;
int ret; int ret;
ret = -EINVAL; ret = -EINVAL;
if (datalen <= 0 || datalen > 32767 || !data) if (datalen <= 0 || datalen > 32767 || !prep->data)
goto error; goto error;
ret = key_payload_reserve(key, datalen); ret = key_payload_reserve(key, datalen);
...@@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen) ...@@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
/* attach the data */ /* attach the data */
upayload->datalen = datalen; upayload->datalen = datalen;
memcpy(upayload->data, data, datalen); memcpy(upayload->data, prep->data, datalen);
rcu_assign_keypointer(key, upayload); rcu_assign_keypointer(key, upayload);
ret = 0; ret = 0;
...@@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate); ...@@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate);
* update a user defined key * update a user defined key
* - the key's semaphore is write-locked * - the key's semaphore is write-locked
*/ */
int user_update(struct key *key, const void *data, size_t datalen) int user_update(struct key *key, struct key_preparsed_payload *prep)
{ {
struct user_key_payload *upayload, *zap; struct user_key_payload *upayload, *zap;
size_t datalen = prep->datalen;
int ret; int ret;
ret = -EINVAL; ret = -EINVAL;
if (datalen <= 0 || datalen > 32767 || !data) if (datalen <= 0 || datalen > 32767 || !prep->data)
goto error; goto error;
/* construct a replacement payload */ /* construct a replacement payload */
...@@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen) ...@@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen)
goto error; goto error;
upayload->datalen = datalen; upayload->datalen = datalen;
memcpy(upayload->data, data, datalen); memcpy(upayload->data, prep->data, datalen);
/* check the quota and attach the new data */ /* check the quota and attach the new data */
zap = upayload; zap = upayload;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment