forked from Minki/linux
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.
This commit is contained in:
commit
61d335dd27
@ -412,6 +412,10 @@ The main syscalls are:
|
||||
to the keyring. In this case, an error will be generated if the process
|
||||
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 type. The payload is plen in size, and plen can be zero for an empty
|
||||
payload.
|
||||
@ -990,6 +994,23 @@ payload contents" for more information.
|
||||
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:
|
||||
|
||||
int validate_key(struct key *key);
|
||||
@ -1114,12 +1135,53 @@ The structure has a number of fields, some of which are mandatory:
|
||||
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.
|
||||
The payload attached need not bear any relation to the data passed to this
|
||||
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
|
||||
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:
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
@ -31,18 +31,18 @@
|
||||
|
||||
/* create a new cifs key */
|
||||
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;
|
||||
int ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
payload = kmalloc(datalen, GFP_KERNEL);
|
||||
payload = kmalloc(prep->datalen, GFP_KERNEL);
|
||||
if (!payload)
|
||||
goto error;
|
||||
|
||||
/* attach the data */
|
||||
memcpy(payload, data, datalen);
|
||||
memcpy(payload, prep->data, prep->datalen);
|
||||
key->payload.data = payload;
|
||||
ret = 0;
|
||||
|
||||
|
@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = {
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
payload = kmalloc(datalen, GFP_KERNEL);
|
||||
payload = kmalloc(prep->datalen, GFP_KERNEL);
|
||||
if (!payload)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(payload, data, datalen);
|
||||
memcpy(payload, prep->data, prep->datalen);
|
||||
key->payload.data = payload;
|
||||
key->datalen = datalen;
|
||||
key->datalen = prep->datalen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -537,19 +537,15 @@ init_cifs_idmap(void)
|
||||
if (!cred)
|
||||
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_USR_VIEW | KEY_USR_READ,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
||||
if (IS_ERR(keyring)) {
|
||||
ret = PTR_ERR(keyring);
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto failed_put_key;
|
||||
|
@ -192,19 +192,15 @@ static int nfs_idmap_init_keyring(void)
|
||||
if (!cred)
|
||||
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_USR_VIEW | KEY_USR_READ,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
||||
if (IS_ERR(keyring)) {
|
||||
ret = PTR_ERR(keyring);
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto failed_put_key;
|
||||
|
@ -35,8 +35,10 @@ struct user_key_payload {
|
||||
extern struct key_type key_type_user;
|
||||
extern struct key_type key_type_logon;
|
||||
|
||||
extern int user_instantiate(struct key *key, const void *data, size_t datalen);
|
||||
extern int user_update(struct key *key, const void *data, size_t datalen);
|
||||
struct key_preparsed_payload;
|
||||
|
||||
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 void user_revoke(struct key *key);
|
||||
extern void user_destroy(struct key *key);
|
||||
|
@ -76,21 +76,6 @@ extern int groups_search(const struct group_info *, kgid_t);
|
||||
extern int in_group_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
|
||||
*
|
||||
@ -139,6 +124,8 @@ struct cred {
|
||||
#ifdef CONFIG_KEYS
|
||||
unsigned char jit_keyring; /* default keyring to attach requested
|
||||
* 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 *request_key_auth; /* assumed request_key authority */
|
||||
struct thread_group_cred *tgcred; /* thread-group shared credentials */
|
||||
|
@ -26,6 +26,27 @@ struct key_construction {
|
||||
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,
|
||||
const char *op, void *aux);
|
||||
|
||||
@ -45,18 +66,28 @@ struct key_type {
|
||||
/* vet a 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
|
||||
* - this method should call key_payload_reserve() to determine if the
|
||||
* 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)
|
||||
* - this method should call key_payload_reserve() to recalculate the
|
||||
* quota consumption
|
||||
* - 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 */
|
||||
int (*match)(const struct key *key, const void *desc);
|
||||
|
@ -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,
|
||||
const struct cred *cred,
|
||||
key_perm_t perm,
|
||||
unsigned long flags,
|
||||
struct key *dest);
|
||||
|
||||
|
127
kernel/cred.c
127
kernel/cred.c
@ -29,17 +29,6 @@
|
||||
|
||||
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
|
||||
*/
|
||||
@ -65,9 +54,6 @@ struct cred init_cred = {
|
||||
.user = INIT_USER,
|
||||
.user_ns = &init_user_ns,
|
||||
.group_info = &init_groups,
|
||||
#ifdef CONFIG_KEYS
|
||||
.tgcred = &init_tgcred,
|
||||
#endif
|
||||
};
|
||||
|
||||
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)
|
||||
#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
|
||||
*/
|
||||
@ -150,9 +106,10 @@ static void put_cred_rcu(struct rcu_head *rcu)
|
||||
#endif
|
||||
|
||||
security_cred_free(cred);
|
||||
key_put(cred->session_keyring);
|
||||
key_put(cred->process_keyring);
|
||||
key_put(cred->thread_keyring);
|
||||
key_put(cred->request_key_auth);
|
||||
release_tgcred(cred);
|
||||
if (cred->group_info)
|
||||
put_group_info(cred->group_info);
|
||||
free_uid(cred->user);
|
||||
@ -246,15 +203,6 @@ struct cred *cred_alloc_blank(void)
|
||||
if (!new)
|
||||
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);
|
||||
#ifdef CONFIG_DEBUG_CREDENTIALS
|
||||
new->magic = CRED_MAGIC;
|
||||
@ -308,9 +256,10 @@ struct cred *prepare_creds(void)
|
||||
get_user_ns(new->user_ns);
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
key_get(new->session_keyring);
|
||||
key_get(new->process_keyring);
|
||||
key_get(new->thread_keyring);
|
||||
key_get(new->request_key_auth);
|
||||
atomic_inc(&new->tgcred->usage);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURITY
|
||||
@ -334,39 +283,20 @@ EXPORT_SYMBOL(prepare_creds);
|
||||
*/
|
||||
struct cred *prepare_exec_creds(void)
|
||||
{
|
||||
struct thread_group_cred *tgcred = NULL;
|
||||
struct cred *new;
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
|
||||
if (!tgcred)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new) {
|
||||
kfree(tgcred);
|
||||
if (!new)
|
||||
return new;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
/* newly exec'd tasks don't get a thread keyring */
|
||||
key_put(new->thread_keyring);
|
||||
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 */
|
||||
key_get(tgcred->session_keyring);
|
||||
tgcred->process_keyring = NULL;
|
||||
|
||||
release_tgcred(new);
|
||||
new->tgcred = tgcred;
|
||||
key_put(new->process_keyring);
|
||||
new->process_keyring = NULL;
|
||||
#endif
|
||||
|
||||
return new;
|
||||
@ -383,9 +313,6 @@ struct cred *prepare_exec_creds(void)
|
||||
*/
|
||||
int copy_creds(struct task_struct *p, unsigned long clone_flags)
|
||||
{
|
||||
#ifdef CONFIG_KEYS
|
||||
struct thread_group_cred *tgcred;
|
||||
#endif
|
||||
struct cred *new;
|
||||
int ret;
|
||||
|
||||
@ -425,22 +352,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
|
||||
install_thread_keyring_to_cred(new);
|
||||
}
|
||||
|
||||
/* we share the process and session keyrings between all the threads in
|
||||
* a process - this is slightly icky as we violate COW credentials a
|
||||
* bit */
|
||||
/* The process keyring is only shared between the threads in a process;
|
||||
* anything outside of those threads doesn't inherit.
|
||||
*/
|
||||
if (!(clone_flags & CLONE_THREAD)) {
|
||||
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
|
||||
if (!tgcred) {
|
||||
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;
|
||||
key_put(new->process_keyring);
|
||||
new->process_keyring = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -643,9 +560,6 @@ void __init cred_init(void)
|
||||
*/
|
||||
struct cred *prepare_kernel_cred(struct task_struct *daemon)
|
||||
{
|
||||
#ifdef CONFIG_KEYS
|
||||
struct thread_group_cred *tgcred;
|
||||
#endif
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
|
||||
@ -653,14 +567,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
|
||||
if (!new)
|
||||
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);
|
||||
|
||||
if (daemon)
|
||||
@ -678,13 +584,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
|
||||
get_group_info(new->group_info);
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
atomic_set(&tgcred->usage, 1);
|
||||
spin_lock_init(&tgcred->lock);
|
||||
tgcred->process_keyring = NULL;
|
||||
tgcred->session_keyring = NULL;
|
||||
new->tgcred = tgcred;
|
||||
new->request_key_auth = NULL;
|
||||
new->session_keyring = NULL;
|
||||
new->process_keyring = NULL;
|
||||
new->thread_keyring = NULL;
|
||||
new->request_key_auth = NULL;
|
||||
new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||||
#endif
|
||||
|
||||
|
@ -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;
|
||||
size_t datalen = prep->datalen;
|
||||
int ret;
|
||||
void *p;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
goto err;
|
||||
|
||||
ret = key_payload_reserve(key, datalen);
|
||||
@ -443,8 +444,8 @@ int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
|
||||
goto err;
|
||||
|
||||
/* TODO ceph_crypto_key_decode should really take const input */
|
||||
p = (void *)data;
|
||||
ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
|
||||
p = (void *)prep->data;
|
||||
ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
|
||||
if (ret < 0)
|
||||
goto err_ckey;
|
||||
|
||||
|
@ -59,13 +59,13 @@ const struct cred *dns_resolver_cache;
|
||||
* "ip1,ip2,...#foo=bar"
|
||||
*/
|
||||
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;
|
||||
unsigned long derrno;
|
||||
int ret;
|
||||
size_t result_len = 0;
|
||||
const char *data = _data, *end, *opt;
|
||||
size_t datalen = prep->datalen, result_len = 0;
|
||||
const char *data = prep->data, *end, *opt;
|
||||
|
||||
kenter("%%%d,%s,'%*.*s',%zu",
|
||||
key->serial, key->description,
|
||||
@ -259,19 +259,15 @@ static int __init init_dns_resolver(void)
|
||||
if (!cred)
|
||||
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_USR_VIEW | KEY_USR_READ,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
||||
if (IS_ERR(keyring)) {
|
||||
ret = PTR_ERR(keyring);
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto failed_put_key;
|
||||
@ -303,3 +299,4 @@ static void __exit exit_dns_resolver(void)
|
||||
module_init(init_dns_resolver)
|
||||
module_exit(exit_dns_resolver)
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
@ -26,8 +26,8 @@
|
||||
#include "ar-internal.h"
|
||||
|
||||
static int rxrpc_vet_description_s(const char *);
|
||||
static int rxrpc_instantiate(struct key *, const void *, size_t);
|
||||
static int rxrpc_instantiate_s(struct key *, const void *, size_t);
|
||||
static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *);
|
||||
static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);
|
||||
static void rxrpc_destroy(struct key *);
|
||||
static void rxrpc_destroy_s(struct key *);
|
||||
static void rxrpc_describe(const struct key *, struct seq_file *);
|
||||
@ -678,7 +678,7 @@ error:
|
||||
*
|
||||
* 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;
|
||||
struct rxrpc_key_token *token, **pp;
|
||||
@ -686,26 +686,26 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
|
||||
u32 kver;
|
||||
int ret;
|
||||
|
||||
_enter("{%x},,%zu", key_serial(key), datalen);
|
||||
_enter("{%x},,%zu", key_serial(key), prep->datalen);
|
||||
|
||||
/* handle a no-security key */
|
||||
if (!data && datalen == 0)
|
||||
if (!prep->data && prep->datalen == 0)
|
||||
return 0;
|
||||
|
||||
/* determine if the XDR payload format is being used */
|
||||
if (datalen > 7 * 4) {
|
||||
ret = rxrpc_instantiate_xdr(key, data, datalen);
|
||||
if (prep->datalen > 7 * 4) {
|
||||
ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);
|
||||
if (ret != -EPROTO)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get the key interface version number */
|
||||
ret = -EINVAL;
|
||||
if (datalen <= 4 || !data)
|
||||
if (prep->datalen <= 4 || !prep->data)
|
||||
goto error;
|
||||
memcpy(&kver, data, sizeof(kver));
|
||||
data += sizeof(kver);
|
||||
datalen -= sizeof(kver);
|
||||
memcpy(&kver, prep->data, sizeof(kver));
|
||||
prep->data += sizeof(kver);
|
||||
prep->datalen -= sizeof(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)
|
||||
|
||||
/* deal with a version 1 key */
|
||||
ret = -EINVAL;
|
||||
if (datalen < sizeof(*v1))
|
||||
if (prep->datalen < sizeof(*v1))
|
||||
goto error;
|
||||
|
||||
v1 = data;
|
||||
if (datalen != sizeof(*v1) + v1->ticket_length)
|
||||
v1 = prep->data;
|
||||
if (prep->datalen != sizeof(*v1) + v1->ticket_length)
|
||||
goto error;
|
||||
|
||||
_debug("SCIX: %u", v1->security_index);
|
||||
@ -784,17 +784,17 @@ error:
|
||||
* instantiate a server secret key
|
||||
* data should be a pointer to the 8-byte secret key
|
||||
*/
|
||||
static int rxrpc_instantiate_s(struct key *key, const void *data,
|
||||
size_t datalen)
|
||||
static int rxrpc_instantiate_s(struct key *key,
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
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;
|
||||
|
||||
memcpy(&key->type_data, data, 8);
|
||||
memcpy(&key->type_data, prep->data, 8);
|
||||
|
||||
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(ci)) {
|
||||
@ -802,7 +802,7 @@ static int rxrpc_instantiate_s(struct key *key, const void *data,
|
||||
return PTR_ERR(ci);
|
||||
}
|
||||
|
||||
if (crypto_blkcipher_setkey(ci, data, 8) < 0)
|
||||
if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
|
||||
BUG();
|
||||
|
||||
key->payload.data = ci;
|
||||
|
@ -773,8 +773,8 @@ static int encrypted_init(struct encrypted_key_payload *epayload,
|
||||
*
|
||||
* On success, return 0. Otherwise return errno.
|
||||
*/
|
||||
static int encrypted_instantiate(struct key *key, const void *data,
|
||||
size_t datalen)
|
||||
static int encrypted_instantiate(struct key *key,
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct encrypted_key_payload *epayload = NULL;
|
||||
char *datablob = NULL;
|
||||
@ -782,16 +782,17 @@ static int encrypted_instantiate(struct key *key, const void *data,
|
||||
char *master_desc = NULL;
|
||||
char *decrypted_datalen = NULL;
|
||||
char *hex_encoded_iv = NULL;
|
||||
size_t datalen = prep->datalen;
|
||||
int ret;
|
||||
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
return -EINVAL;
|
||||
|
||||
datablob = kmalloc(datalen + 1, GFP_KERNEL);
|
||||
if (!datablob)
|
||||
return -ENOMEM;
|
||||
datablob[datalen] = 0;
|
||||
memcpy(datablob, data, datalen);
|
||||
memcpy(datablob, prep->data, datalen);
|
||||
ret = datablob_parse(datablob, &format, &master_desc,
|
||||
&decrypted_datalen, &hex_encoded_iv);
|
||||
if (ret < 0)
|
||||
@ -834,16 +835,17 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
|
||||
*
|
||||
* 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 *new_epayload;
|
||||
char *buf;
|
||||
char *new_master_desc = NULL;
|
||||
const char *format = NULL;
|
||||
size_t datalen = prep->datalen;
|
||||
int ret = 0;
|
||||
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
return -EINVAL;
|
||||
|
||||
buf = kmalloc(datalen + 1, GFP_KERNEL);
|
||||
@ -851,7 +853,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
|
||||
return -ENOMEM;
|
||||
|
||||
buf[datalen] = 0;
|
||||
memcpy(buf, data, datalen);
|
||||
memcpy(buf, prep->data, datalen);
|
||||
ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve);
|
||||
* key_construction_mutex.
|
||||
*/
|
||||
static int __key_instantiate_and_link(struct key *key,
|
||||
const void *data,
|
||||
size_t datalen,
|
||||
struct key_preparsed_payload *prep,
|
||||
struct key *keyring,
|
||||
struct key *authkey,
|
||||
unsigned long *_prealloc)
|
||||
@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key,
|
||||
/* can't instantiate twice */
|
||||
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
|
||||
/* instantiate the key */
|
||||
ret = key->type->instantiate(key, data, datalen);
|
||||
ret = key->type->instantiate(key, prep);
|
||||
|
||||
if (ret == 0) {
|
||||
/* mark the key as being instantiated */
|
||||
@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key,
|
||||
struct key *keyring,
|
||||
struct key *authkey)
|
||||
{
|
||||
struct key_preparsed_payload prep;
|
||||
unsigned long prealloc;
|
||||
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) {
|
||||
ret = __key_link_begin(keyring, key->type, key->description,
|
||||
&prealloc);
|
||||
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);
|
||||
|
||||
if (keyring)
|
||||
__key_link_end(keyring, key->type, prealloc);
|
||||
|
||||
error_free_preparse:
|
||||
if (key->type->preparse)
|
||||
key->type->free_preparse(&prep);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype)
|
||||
* if we get an error.
|
||||
*/
|
||||
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);
|
||||
int ret;
|
||||
@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
|
||||
|
||||
down_write(&key->sem);
|
||||
|
||||
ret = key->type->update(key, payload, plen);
|
||||
ret = key->type->update(key, prep);
|
||||
if (ret == 0)
|
||||
/* updating a negative key instantiates it */
|
||||
clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
||||
@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
||||
unsigned long flags)
|
||||
{
|
||||
unsigned long prealloc;
|
||||
struct key_preparsed_payload prep;
|
||||
const struct cred *cred = current_cred();
|
||||
struct key_type *ktype;
|
||||
struct key *keyring, *key = NULL;
|
||||
@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
||||
}
|
||||
|
||||
key_ref = ERR_PTR(-EINVAL);
|
||||
if (!ktype->match || !ktype->instantiate)
|
||||
goto error_2;
|
||||
if (!ktype->match || !ktype->instantiate ||
|
||||
(!description && !ktype->preparse))
|
||||
goto error_put_type;
|
||||
|
||||
keyring = key_ref_to_ptr(keyring_ref);
|
||||
|
||||
@ -798,18 +814,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
||||
|
||||
key_ref = ERR_PTR(-ENOTDIR);
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto error_2;
|
||||
if (ret < 0) {
|
||||
key_ref = ERR_PTR(ret);
|
||||
goto error_free_prep;
|
||||
}
|
||||
|
||||
/* if we're going to allocate a new key, we're going to have
|
||||
* to modify the keyring */
|
||||
ret = key_permission(keyring_ref, KEY_WRITE);
|
||||
if (ret < 0) {
|
||||
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
|
||||
@ -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 (perm == KEY_PERM_UNDEF) {
|
||||
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)
|
||||
perm |= KEY_POS_READ | KEY_USR_READ;
|
||||
perm |= KEY_POS_READ;
|
||||
|
||||
if (ktype == &key_type_keyring || ktype->update)
|
||||
perm |= KEY_USR_WRITE;
|
||||
perm |= KEY_POS_WRITE;
|
||||
}
|
||||
|
||||
/* allocate a new key */
|
||||
@ -840,23 +875,25 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
||||
perm, flags);
|
||||
if (IS_ERR(key)) {
|
||||
key_ref = ERR_CAST(key);
|
||||
goto error_3;
|
||||
goto error_link_end;
|
||||
}
|
||||
|
||||
/* instantiate it and link it into the target keyring */
|
||||
ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
|
||||
&prealloc);
|
||||
ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc);
|
||||
if (ret < 0) {
|
||||
key_put(key);
|
||||
key_ref = ERR_PTR(ret);
|
||||
goto error_3;
|
||||
goto error_link_end;
|
||||
}
|
||||
|
||||
key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
|
||||
|
||||
error_3:
|
||||
error_link_end:
|
||||
__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);
|
||||
error:
|
||||
return key_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
|
||||
*/
|
||||
__key_link_end(keyring, ktype, prealloc);
|
||||
key_type_put(ktype);
|
||||
|
||||
key_ref = __key_update(key_ref, payload, plen);
|
||||
goto error;
|
||||
key_ref = __key_update(key_ref, &prep);
|
||||
goto error_free_prep;
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct key_preparsed_payload prep;
|
||||
struct key *key = key_ref_to_ptr(key_ref);
|
||||
int ret;
|
||||
|
||||
@ -900,17 +937,30 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
||||
|
||||
/* attempt to update it if supported */
|
||||
ret = -EOPNOTSUPP;
|
||||
if (key->type->update) {
|
||||
if (!key->type->update)
|
||||
goto error;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
down_write(&key->sem);
|
||||
|
||||
ret = key->type->update(key, payload, plen);
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
* 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.
|
||||
*
|
||||
* If successful, the new key's serial number is returned, otherwise an error
|
||||
@ -72,11 +75,18 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
description = NULL;
|
||||
if (_description) {
|
||||
description = strndup_user(_description, PAGE_SIZE);
|
||||
if (IS_ERR(description)) {
|
||||
ret = PTR_ERR(description);
|
||||
goto error;
|
||||
}
|
||||
if (!*description) {
|
||||
kfree(description);
|
||||
description = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* pull the payload in if one was supplied */
|
||||
payload = NULL;
|
||||
@ -1112,12 +1122,12 @@ long keyctl_instantiate_key_iov(key_serial_t id,
|
||||
ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
|
||||
ARRAY_SIZE(iovstack), iovstack, &iov);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
if (ret == 0)
|
||||
goto no_payload_free;
|
||||
|
||||
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
|
||||
|
||||
err:
|
||||
if (iov != iovstack)
|
||||
kfree(iov);
|
||||
return ret;
|
||||
@ -1475,7 +1485,8 @@ long keyctl_session_to_parent(void)
|
||||
goto error_keyring;
|
||||
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);
|
||||
|
||||
me = current;
|
||||
@ -1500,7 +1511,7 @@ long keyctl_session_to_parent(void)
|
||||
mycred = current_cred();
|
||||
pcred = __task_cred(parent);
|
||||
if (mycred == pcred ||
|
||||
mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) {
|
||||
mycred->session_keyring == pcred->session_keyring) {
|
||||
ret = 0;
|
||||
goto unlock;
|
||||
}
|
||||
@ -1516,9 +1527,9 @@ long keyctl_session_to_parent(void)
|
||||
goto unlock;
|
||||
|
||||
/* the keyrings must have the same UID */
|
||||
if ((pcred->tgcred->session_keyring &&
|
||||
pcred->tgcred->session_keyring->uid != mycred->euid) ||
|
||||
mycred->tgcred->session_keyring->uid != mycred->euid)
|
||||
if ((pcred->session_keyring &&
|
||||
pcred->session_keyring->uid != mycred->euid) ||
|
||||
mycred->session_keyring->uid != mycred->euid)
|
||||
goto unlock;
|
||||
|
||||
/* cancel an already pending keyring replacement */
|
||||
|
@ -66,7 +66,7 @@ static inline unsigned keyring_hash(const char *desc)
|
||||
* operations.
|
||||
*/
|
||||
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 void keyring_revoke(struct key *keyring);
|
||||
static void keyring_destroy(struct key *keyring);
|
||||
@ -121,12 +121,12 @@ static void keyring_publish_name(struct key *keyring)
|
||||
* Returns 0 on success, -EINVAL if given any data.
|
||||
*/
|
||||
static int keyring_instantiate(struct key *keyring,
|
||||
const void *data, size_t datalen)
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (datalen == 0) {
|
||||
if (prep->datalen == 0) {
|
||||
/* make the keyring available by name if it has one */
|
||||
keyring_publish_name(keyring);
|
||||
ret = 0;
|
||||
@ -257,17 +257,14 @@ error:
|
||||
* Allocate a keyring and link into the destination keyring.
|
||||
*/
|
||||
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
|
||||
const struct cred *cred, unsigned long flags,
|
||||
struct key *dest)
|
||||
const struct cred *cred, key_perm_t perm,
|
||||
unsigned long flags, struct key *dest)
|
||||
{
|
||||
struct key *keyring;
|
||||
int ret;
|
||||
|
||||
keyring = key_alloc(&key_type_keyring, description,
|
||||
uid, gid, cred,
|
||||
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
|
||||
flags);
|
||||
|
||||
uid, gid, cred, perm, flags);
|
||||
if (!IS_ERR(keyring)) {
|
||||
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
|
||||
if (ret < 0) {
|
||||
@ -278,6 +275,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
|
||||
|
||||
return keyring;
|
||||
}
|
||||
EXPORT_SYMBOL(keyring_alloc);
|
||||
|
||||
/**
|
||||
* keyring_search_aux - Search a keyring tree for a key matching some criteria
|
||||
|
@ -46,9 +46,11 @@ int install_user_keyrings(void)
|
||||
struct user_struct *user;
|
||||
const struct cred *cred;
|
||||
struct key *uid_keyring, *session_keyring;
|
||||
key_perm_t user_keyring_perm;
|
||||
char buf[20];
|
||||
int ret;
|
||||
|
||||
user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL;
|
||||
cred = current_cred();
|
||||
user = cred->user;
|
||||
|
||||
@ -72,8 +74,8 @@ int install_user_keyrings(void)
|
||||
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);
|
||||
cred, user_keyring_perm,
|
||||
KEY_ALLOC_IN_QUOTA, NULL);
|
||||
if (IS_ERR(uid_keyring)) {
|
||||
ret = PTR_ERR(uid_keyring);
|
||||
goto error;
|
||||
@ -88,7 +90,8 @@ int install_user_keyrings(void)
|
||||
if (IS_ERR(session_keyring)) {
|
||||
session_keyring =
|
||||
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)) {
|
||||
ret = PTR_ERR(session_keyring);
|
||||
goto error_release;
|
||||
@ -129,6 +132,7 @@ int install_thread_keyring_to_cred(struct cred *new)
|
||||
struct key *keyring;
|
||||
|
||||
keyring = keyring_alloc("_tid", new->uid, new->gid, new,
|
||||
KEY_POS_ALL | KEY_USR_VIEW,
|
||||
KEY_ALLOC_QUOTA_OVERRUN, NULL);
|
||||
if (IS_ERR(keyring))
|
||||
return PTR_ERR(keyring);
|
||||
@ -169,27 +173,18 @@ static int install_thread_keyring(void)
|
||||
int install_process_keyring_to_cred(struct cred *new)
|
||||
{
|
||||
struct key *keyring;
|
||||
int ret;
|
||||
|
||||
if (new->tgcred->process_keyring)
|
||||
if (new->process_keyring)
|
||||
return -EEXIST;
|
||||
|
||||
keyring = keyring_alloc("_pid", new->uid, new->gid,
|
||||
new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
|
||||
keyring = keyring_alloc("_pid", new->uid, new->gid, new,
|
||||
KEY_POS_ALL | KEY_USR_VIEW,
|
||||
KEY_ALLOC_QUOTA_OVERRUN, NULL);
|
||||
if (IS_ERR(keyring))
|
||||
return PTR_ERR(keyring);
|
||||
|
||||
spin_lock_irq(&new->tgcred->lock);
|
||||
if (!new->tgcred->process_keyring) {
|
||||
new->tgcred->process_keyring = keyring;
|
||||
keyring = NULL;
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -EEXIST;
|
||||
}
|
||||
spin_unlock_irq(&new->tgcred->lock);
|
||||
key_put(keyring);
|
||||
return ret;
|
||||
new->process_keyring = keyring;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -230,11 +225,12 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
|
||||
/* create an empty session keyring */
|
||||
if (!keyring) {
|
||||
flags = KEY_ALLOC_QUOTA_OVERRUN;
|
||||
if (cred->tgcred->session_keyring)
|
||||
if (cred->session_keyring)
|
||||
flags = KEY_ALLOC_IN_QUOTA;
|
||||
|
||||
keyring = keyring_alloc("_ses", cred->uid, cred->gid,
|
||||
cred, flags, NULL);
|
||||
keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
|
||||
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
|
||||
flags, NULL);
|
||||
if (IS_ERR(keyring))
|
||||
return PTR_ERR(keyring);
|
||||
} else {
|
||||
@ -242,17 +238,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
|
||||
}
|
||||
|
||||
/* install the keyring */
|
||||
spin_lock_irq(&cred->tgcred->lock);
|
||||
old = cred->tgcred->session_keyring;
|
||||
rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
|
||||
spin_unlock_irq(&cred->tgcred->lock);
|
||||
old = cred->session_keyring;
|
||||
rcu_assign_pointer(cred->session_keyring, keyring);
|
||||
|
||||
/* 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();
|
||||
if (old)
|
||||
key_put(old);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -357,8 +347,6 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
|
||||
|
||||
switch (PTR_ERR(key_ref)) {
|
||||
case -EAGAIN: /* no key */
|
||||
if (ret)
|
||||
break;
|
||||
case -ENOKEY: /* negative key */
|
||||
ret = key_ref;
|
||||
break;
|
||||
@ -369,9 +357,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
|
||||
}
|
||||
|
||||
/* search the process keyring second */
|
||||
if (cred->tgcred->process_keyring) {
|
||||
if (cred->process_keyring) {
|
||||
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);
|
||||
if (!IS_ERR(key_ref))
|
||||
goto found;
|
||||
@ -390,12 +378,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
|
||||
}
|
||||
|
||||
/* search the session keyring */
|
||||
if (cred->tgcred->session_keyring) {
|
||||
if (cred->session_keyring) {
|
||||
rcu_read_lock();
|
||||
key_ref = keyring_search_aux(
|
||||
make_key_ref(rcu_dereference(
|
||||
cred->tgcred->session_keyring),
|
||||
1),
|
||||
make_key_ref(rcu_dereference(cred->session_keyring), 1),
|
||||
cred, type, description, match, no_state_check);
|
||||
rcu_read_unlock();
|
||||
|
||||
@ -565,7 +551,7 @@ try_again:
|
||||
break;
|
||||
|
||||
case KEY_SPEC_PROCESS_KEYRING:
|
||||
if (!cred->tgcred->process_keyring) {
|
||||
if (!cred->process_keyring) {
|
||||
if (!(lflags & KEY_LOOKUP_CREATE))
|
||||
goto error;
|
||||
|
||||
@ -577,13 +563,13 @@ try_again:
|
||||
goto reget_creds;
|
||||
}
|
||||
|
||||
key = cred->tgcred->process_keyring;
|
||||
key = cred->process_keyring;
|
||||
atomic_inc(&key->usage);
|
||||
key_ref = make_key_ref(key, 1);
|
||||
break;
|
||||
|
||||
case KEY_SPEC_SESSION_KEYRING:
|
||||
if (!cred->tgcred->session_keyring) {
|
||||
if (!cred->session_keyring) {
|
||||
/* always install a session keyring upon access if one
|
||||
* doesn't exist yet */
|
||||
ret = install_user_keyrings();
|
||||
@ -598,7 +584,7 @@ try_again:
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
goto reget_creds;
|
||||
} else if (cred->tgcred->session_keyring ==
|
||||
} else if (cred->session_keyring ==
|
||||
cred->user->session_keyring &&
|
||||
lflags & KEY_LOOKUP_CREATE) {
|
||||
ret = join_session_keyring(NULL);
|
||||
@ -608,7 +594,7 @@ try_again:
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
key = rcu_dereference(cred->tgcred->session_keyring);
|
||||
key = rcu_dereference(cred->session_keyring);
|
||||
atomic_inc(&key->usage);
|
||||
rcu_read_unlock();
|
||||
key_ref = make_key_ref(key, 1);
|
||||
@ -768,12 +754,6 @@ long join_session_keyring(const char *name)
|
||||
struct key *keyring;
|
||||
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();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
@ -785,7 +765,7 @@ long join_session_keyring(const char *name)
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
serial = new->tgcred->session_keyring->serial;
|
||||
serial = new->session_keyring->serial;
|
||||
ret = commit_creds(new);
|
||||
if (ret == 0)
|
||||
ret = serial;
|
||||
@ -799,7 +779,9 @@ long join_session_keyring(const char *name)
|
||||
keyring = find_keyring_by_name(name, false);
|
||||
if (PTR_ERR(keyring) == -ENOKEY) {
|
||||
/* not found - try and create a new one */
|
||||
keyring = keyring_alloc(name, old->uid, old->gid, old,
|
||||
keyring = keyring_alloc(
|
||||
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)) {
|
||||
ret = PTR_ERR(keyring);
|
||||
@ -808,6 +790,9 @@ long join_session_keyring(const char *name)
|
||||
} else if (IS_ERR(keyring)) {
|
||||
ret = PTR_ERR(keyring);
|
||||
goto error2;
|
||||
} else if (keyring == new->session_keyring) {
|
||||
ret = 0;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
/* we've got a keyring - now to install it */
|
||||
@ -864,8 +849,7 @@ void key_change_session_keyring(struct callback_head *twork)
|
||||
|
||||
new->jit_keyring = old->jit_keyring;
|
||||
new->thread_keyring = key_get(old->thread_keyring);
|
||||
new->tgcred->tgid = old->tgcred->tgid;
|
||||
new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
|
||||
new->process_keyring = key_get(old->process_keyring);
|
||||
|
||||
security_transfer_creds(new, old);
|
||||
|
||||
|
@ -126,6 +126,7 @@ static int call_sbin_request_key(struct key_construction *cons,
|
||||
|
||||
cred = get_current_cred();
|
||||
keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
|
||||
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
|
||||
KEY_ALLOC_QUOTA_OVERRUN, NULL);
|
||||
put_cred(cred);
|
||||
if (IS_ERR(keyring)) {
|
||||
@ -150,12 +151,12 @@ static int call_sbin_request_key(struct key_construction *cons,
|
||||
cred->thread_keyring ? cred->thread_keyring->serial : 0);
|
||||
|
||||
prkey = 0;
|
||||
if (cred->tgcred->process_keyring)
|
||||
prkey = cred->tgcred->process_keyring->serial;
|
||||
if (cred->process_keyring)
|
||||
prkey = cred->process_keyring->serial;
|
||||
sprintf(keyring_str[1], "%d", prkey);
|
||||
|
||||
rcu_read_lock();
|
||||
session = rcu_dereference(cred->tgcred->session_keyring);
|
||||
session = rcu_dereference(cred->session_keyring);
|
||||
if (!session)
|
||||
session = cred->user->session_keyring;
|
||||
sskey = session->serial;
|
||||
@ -297,14 +298,14 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
|
||||
break;
|
||||
|
||||
case KEY_REQKEY_DEFL_PROCESS_KEYRING:
|
||||
dest_keyring = key_get(cred->tgcred->process_keyring);
|
||||
dest_keyring = key_get(cred->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_dereference(cred->session_keyring));
|
||||
rcu_read_unlock();
|
||||
|
||||
if (dest_keyring)
|
||||
@ -347,6 +348,7 @@ static int construct_alloc_key(struct key_type *type,
|
||||
const struct cred *cred = current_cred();
|
||||
unsigned long prealloc;
|
||||
struct key *key;
|
||||
key_perm_t perm;
|
||||
key_ref_t key_ref;
|
||||
int ret;
|
||||
|
||||
@ -355,8 +357,15 @@ static int construct_alloc_key(struct key_type *type,
|
||||
*_key = NULL;
|
||||
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_POS_ALL, flags);
|
||||
perm, flags);
|
||||
if (IS_ERR(key))
|
||||
goto alloc_failed;
|
||||
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include <asm/uaccess.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_revoke(struct key *);
|
||||
static void request_key_auth_destroy(struct key *);
|
||||
@ -42,10 +43,9 @@ struct key_type key_type_request_key_auth = {
|
||||
* Instantiate a request-key authorisation key.
|
||||
*/
|
||||
static int request_key_auth_instantiate(struct key *key,
|
||||
const void *data,
|
||||
size_t datalen)
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
key->payload.data = (struct request_key_auth *) data;
|
||||
key->payload.data = (struct request_key_auth *)prep->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -895,23 +895,24 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
|
||||
*
|
||||
* On success, return 0. Otherwise return errno.
|
||||
*/
|
||||
static int trusted_instantiate(struct key *key, const void *data,
|
||||
size_t datalen)
|
||||
static int trusted_instantiate(struct key *key,
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct trusted_key_payload *payload = NULL;
|
||||
struct trusted_key_options *options = NULL;
|
||||
size_t datalen = prep->datalen;
|
||||
char *datablob;
|
||||
int ret = 0;
|
||||
int key_cmd;
|
||||
size_t key_len;
|
||||
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
return -EINVAL;
|
||||
|
||||
datablob = kmalloc(datalen + 1, GFP_KERNEL);
|
||||
if (!datablob)
|
||||
return -ENOMEM;
|
||||
memcpy(datablob, data, datalen);
|
||||
memcpy(datablob, prep->data, datalen);
|
||||
datablob[datalen] = '\0';
|
||||
|
||||
options = trusted_options_alloc();
|
||||
@ -981,17 +982,18 @@ static void trusted_rcu_free(struct rcu_head *rcu)
|
||||
/*
|
||||
* 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 *new_p;
|
||||
struct trusted_key_options *new_o;
|
||||
size_t datalen = prep->datalen;
|
||||
char *datablob;
|
||||
int ret = 0;
|
||||
|
||||
if (!p->migratable)
|
||||
return -EPERM;
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
return -EINVAL;
|
||||
|
||||
datablob = kmalloc(datalen + 1, GFP_KERNEL);
|
||||
@ -1008,7 +1010,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(datablob, data, datalen);
|
||||
memcpy(datablob, prep->data, datalen);
|
||||
datablob[datalen] = '\0';
|
||||
ret = datablob_parse(datablob, new_p, new_o);
|
||||
if (ret != Opt_update) {
|
||||
|
@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon);
|
||||
/*
|
||||
* 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;
|
||||
size_t datalen = prep->datalen;
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
goto error;
|
||||
|
||||
ret = key_payload_reserve(key, datalen);
|
||||
@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
|
||||
|
||||
/* attach the data */
|
||||
upayload->datalen = datalen;
|
||||
memcpy(upayload->data, data, datalen);
|
||||
memcpy(upayload->data, prep->data, datalen);
|
||||
rcu_assign_keypointer(key, upayload);
|
||||
ret = 0;
|
||||
|
||||
@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate);
|
||||
* update a user defined key
|
||||
* - 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;
|
||||
size_t datalen = prep->datalen;
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
goto error;
|
||||
|
||||
/* construct a replacement payload */
|
||||
@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen)
|
||||
goto error;
|
||||
|
||||
upayload->datalen = datalen;
|
||||
memcpy(upayload->data, data, datalen);
|
||||
memcpy(upayload->data, prep->data, datalen);
|
||||
|
||||
/* check the quota and attach the new data */
|
||||
zap = upayload;
|
||||
|
Loading…
Reference in New Issue
Block a user