Skip to content

Commit

Permalink
Merge commit 'tags/keys-fixes-20171018' into fixes-v4.14-rc5
Browse files Browse the repository at this point in the history
  • Loading branch information
James Morris committed Oct 19, 2017
2 parents 73d3393 + 68a1fdb commit 494b9ae
Show file tree
Hide file tree
Showing 23 changed files with 168 additions and 80 deletions.
4 changes: 3 additions & 1 deletion crypto/asymmetric_keys/asymmetric_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ struct key *find_asymmetric_key(struct key *keyring,
char *req, *p;
int len;

BUG_ON(!id_0 && !id_1);

if (id_0) {
lookup = id_0->data;
len = id_0->len;
Expand Down Expand Up @@ -105,7 +107,7 @@ struct key *find_asymmetric_key(struct key *keyring,
if (id_0 && id_1) {
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);

if (!kids->id[0]) {
if (!kids->id[1]) {
pr_debug("First ID matches, but second is missing\n");
goto reject;
}
Expand Down
3 changes: 3 additions & 0 deletions crypto/asymmetric_keys/pkcs7_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg)
bool want = false;

sinfo = msg->signed_infos;
if (!sinfo)
goto inconsistent;

if (sinfo->authattrs) {
want = true;
msg->have_authattrs = true;
Expand Down
5 changes: 5 additions & 0 deletions fs/crypto/keyinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ static int validate_user_key(struct fscrypt_info *crypt_info,
goto out;
}
ukp = user_key_payload_locked(keyring_key);
if (!ukp) {
/* key was revoked before we acquired its semaphore */
res = -EKEYREVOKED;
goto out;
}
if (ukp->datalen != sizeof(struct fscrypt_key)) {
res = -EINVAL;
goto out;
Expand Down
24 changes: 17 additions & 7 deletions fs/ecryptfs/ecryptfs_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,16 @@ struct ecryptfs_page_crypt_context {
static inline struct ecryptfs_auth_tok *
ecryptfs_get_encrypted_key_payload_data(struct key *key)
{
if (key->type == &key_type_encrypted)
return (struct ecryptfs_auth_tok *)
(&((struct encrypted_key_payload *)key->payload.data[0])->payload_data);
else
struct encrypted_key_payload *payload;

if (key->type != &key_type_encrypted)
return NULL;

payload = key->payload.data[0];
if (!payload)
return ERR_PTR(-EKEYREVOKED);

return (struct ecryptfs_auth_tok *)payload->payload_data;
}

static inline struct key *ecryptfs_get_encrypted_key(char *sig)
Expand All @@ -114,12 +119,17 @@ static inline struct ecryptfs_auth_tok *
ecryptfs_get_key_payload_data(struct key *key)
{
struct ecryptfs_auth_tok *auth_tok;
struct user_key_payload *ukp;

auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
if (!auth_tok)
return (struct ecryptfs_auth_tok *)user_key_payload_locked(key)->data;
else
if (auth_tok)
return auth_tok;

ukp = user_key_payload_locked(key);
if (!ukp)
return ERR_PTR(-EKEYREVOKED);

return (struct ecryptfs_auth_tok *)ukp->data;
}

#define ECRYPTFS_MAX_KEYSET_SIZE 1024
Expand Down
9 changes: 8 additions & 1 deletion fs/ecryptfs/keystore.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,8 @@ static int ecryptfs_verify_version(u16 version)
* @auth_tok_key: key containing the authentication token
* @auth_tok: authentication token
*
* Returns zero on valid auth tok; -EINVAL otherwise
* Returns zero on valid auth tok; -EINVAL if the payload is invalid; or
* -EKEYREVOKED if the key was revoked before we acquired its semaphore.
*/
static int
ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key,
Expand All @@ -468,6 +469,12 @@ ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key,
int rc = 0;

(*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key);
if (IS_ERR(*auth_tok)) {
rc = PTR_ERR(*auth_tok);
*auth_tok = NULL;
goto out;
}

if (ecryptfs_verify_version((*auth_tok)->version)) {
printk(KERN_ERR "Data structure version mismatch. Userspace "
"tools must match eCryptfs kernel module with major "
Expand Down
7 changes: 7 additions & 0 deletions fs/fscache/object-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,13 @@ static void fscache_objlist_config(struct fscache_objlist_data *data)
rcu_read_lock();

confkey = user_key_payload_rcu(key);
if (!confkey) {
/* key was revoked */
rcu_read_unlock();
key_put(key);
goto no_config;
}

buf = confkey->data;

for (len = confkey->datalen - 1; len >= 0; len--) {
Expand Down
47 changes: 30 additions & 17 deletions include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ struct key_restriction {
struct key_type *keytype;
};

enum key_state {
KEY_IS_UNINSTANTIATED,
KEY_IS_POSITIVE, /* Positively instantiated */
};

/*****************************************************************************/
/*
* authentication token / access credential / keyring
Expand Down Expand Up @@ -169,25 +174,24 @@ struct key {
* - may not match RCU dereferenced payload
* - payload should contain own length
*/
short state; /* Key state (+) or rejection error (-) */

#ifdef KEY_DEBUGGING
unsigned magic;
#define KEY_DEBUG_MAGIC 0x18273645u
#endif

unsigned long flags; /* status flags (change with bitops) */
#define KEY_FLAG_INSTANTIATED 0 /* set if key has been instantiated */
#define KEY_FLAG_DEAD 1 /* set if key type has been deleted */
#define KEY_FLAG_REVOKED 2 /* set if key had been revoked */
#define KEY_FLAG_IN_QUOTA 3 /* set if key consumes quota */
#define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */
#define KEY_FLAG_NEGATIVE 5 /* set if key is negative */
#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */
#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */
#define KEY_FLAG_BUILTIN 8 /* set if key is built in to the kernel */
#define KEY_FLAG_ROOT_CAN_INVAL 9 /* set if key can be invalidated by root without permission */
#define KEY_FLAG_KEEP 10 /* set if key should not be removed */
#define KEY_FLAG_UID_KEYRING 11 /* set if key is a user or user session keyring */
#define KEY_FLAG_DEAD 0 /* set if key type has been deleted */
#define KEY_FLAG_REVOKED 1 /* set if key had been revoked */
#define KEY_FLAG_IN_QUOTA 2 /* set if key consumes quota */
#define KEY_FLAG_USER_CONSTRUCT 3 /* set if key is being constructed in userspace */
#define KEY_FLAG_ROOT_CAN_CLEAR 4 /* set if key can be cleared by root without permission */
#define KEY_FLAG_INVALIDATED 5 /* set if key has been invalidated */
#define KEY_FLAG_BUILTIN 6 /* set if key is built in to the kernel */
#define KEY_FLAG_ROOT_CAN_INVAL 7 /* set if key can be invalidated by root without permission */
#define KEY_FLAG_KEEP 8 /* set if key should not be removed */
#define KEY_FLAG_UID_KEYRING 9 /* set if key is a user or user session keyring */

/* the key type and key description string
* - the desc is used to match a key against search criteria
Expand All @@ -213,7 +217,6 @@ struct key {
struct list_head name_link;
struct assoc_array keys;
};
int reject_error;
};

/* This is set on a keyring to restrict the addition of a link to a key
Expand Down Expand Up @@ -353,17 +356,27 @@ extern void key_set_timeout(struct key *, unsigned);
#define KEY_NEED_SETATTR 0x20 /* Require permission to change attributes */
#define KEY_NEED_ALL 0x3f /* All the above permissions */

static inline short key_read_state(const struct key *key)
{
/* Barrier versus mark_key_instantiated(). */
return smp_load_acquire(&key->state);
}

/**
* key_is_instantiated - Determine if a key has been positively instantiated
* key_is_positive - Determine if a key has been positively instantiated
* @key: The key to check.
*
* Return true if the specified key has been positively instantiated, false
* otherwise.
*/
static inline bool key_is_instantiated(const struct key *key)
static inline bool key_is_positive(const struct key *key)
{
return key_read_state(key) == KEY_IS_POSITIVE;
}

static inline bool key_is_negative(const struct key *key)
{
return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
!test_bit(KEY_FLAG_NEGATIVE, &key->flags);
return key_read_state(key) < 0;
}

#define dereference_key_rcu(KEY) \
Expand Down
6 changes: 6 additions & 0 deletions lib/digsig.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ static int digsig_verify_rsa(struct key *key,
down_read(&key->sem);
ukp = user_key_payload_locked(key);

if (!ukp) {
/* key was revoked before we acquired its semaphore */
err = -EKEYREVOKED;
goto err1;
}

if (ukp->datalen < sizeof(*pkh))
goto err1;

Expand Down
2 changes: 1 addition & 1 deletion net/dns_resolver/dns_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ static int dns_resolver_match_preparse(struct key_match_data *match_data)
static void dns_resolver_describe(const struct key *key, struct seq_file *m)
{
seq_puts(m, key->description);
if (key_is_instantiated(key)) {
if (key_is_positive(key)) {
int err = PTR_ERR(key->payload.data[dns_key_error]);

if (err)
Expand Down
1 change: 1 addition & 0 deletions security/keys/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ config BIG_KEYS
bool "Large payload keys"
depends on KEYS
depends on TMPFS
select CRYPTO
select CRYPTO_AES
select CRYPTO_GCM
help
Expand Down
4 changes: 2 additions & 2 deletions security/keys/big_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ void big_key_revoke(struct key *key)

/* clear the quota */
key_payload_reserve(key, 0);
if (key_is_instantiated(key) &&
if (key_is_positive(key) &&
(size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
vfs_truncate(path, 0);
}
Expand Down Expand Up @@ -279,7 +279,7 @@ void big_key_describe(const struct key *key, struct seq_file *m)

seq_puts(m, key->description);

if (key_is_instantiated(key))
if (key_is_positive(key))
seq_printf(m, ": %zu [%s]",
datalen,
datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
Expand Down
9 changes: 8 additions & 1 deletion security/keys/encrypted-keys/encrypted.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,13 @@ static struct key *request_user_key(const char *master_desc, const u8 **master_k

down_read(&ukey->sem);
upayload = user_key_payload_locked(ukey);
if (!upayload) {
/* key was revoked before we acquired its semaphore */
up_read(&ukey->sem);
key_put(ukey);
ukey = ERR_PTR(-EKEYREVOKED);
goto error;
}
*master_key = upayload->data;
*master_keylen = upayload->datalen;
error:
Expand Down Expand Up @@ -847,7 +854,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
size_t datalen = prep->datalen;
int ret = 0;

if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
if (key_is_negative(key))
return -ENOKEY;
if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
Expand Down
8 changes: 4 additions & 4 deletions security/keys/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
while (!list_empty(keys)) {
struct key *key =
list_entry(keys->next, struct key, graveyard_link);
short state = key->state;

list_del(&key->graveyard_link);

kdebug("- %u", key->serial);
key_check(key);

/* Throw away the key data if the key is instantiated */
if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
!test_bit(KEY_FLAG_NEGATIVE, &key->flags) &&
key->type->destroy)
if (state == KEY_IS_POSITIVE && key->type->destroy)
key->type->destroy(key);

security_key_free(key);
Expand All @@ -151,7 +151,7 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
}

atomic_dec(&key->user->nkeys);
if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
if (state != KEY_IS_UNINSTANTIATED)
atomic_dec(&key->user->nikeys);

key_user_put(key->user);
Expand Down
41 changes: 30 additions & 11 deletions security/keys/key.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,18 @@ int key_payload_reserve(struct key *key, size_t datalen)
}
EXPORT_SYMBOL(key_payload_reserve);

/*
* Change the key state to being instantiated.
*/
static void mark_key_instantiated(struct key *key, int reject_error)
{
/* Commit the payload before setting the state; barrier versus
* key_read_state().
*/
smp_store_release(&key->state,
(reject_error < 0) ? reject_error : KEY_IS_POSITIVE);
}

/*
* Instantiate a key and link it into the target keyring atomically. Must be
* called with the target keyring's semaphore writelocked. The target key's
Expand All @@ -424,14 +436,14 @@ static int __key_instantiate_and_link(struct key *key,
mutex_lock(&key_construction_mutex);

/* can't instantiate twice */
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
if (key->state == KEY_IS_UNINSTANTIATED) {
/* instantiate the key */
ret = key->type->instantiate(key, prep);

if (ret == 0) {
/* mark the key as being instantiated */
atomic_inc(&key->user->nikeys);
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
mark_key_instantiated(key, 0);

if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
awaken = 1;
Expand Down Expand Up @@ -577,13 +589,10 @@ int key_reject_and_link(struct key *key,
mutex_lock(&key_construction_mutex);

/* can't instantiate twice */
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
if (key->state == KEY_IS_UNINSTANTIATED) {
/* mark the key as being negatively instantiated */
atomic_inc(&key->user->nikeys);
key->reject_error = -error;
smp_wmb();
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
mark_key_instantiated(key, -error);
now = current_kernel_time();
key->expiry = now.tv_sec + timeout;
key_schedule_gc(key->expiry + key_gc_delay);
Expand Down Expand Up @@ -752,8 +761,8 @@ static inline key_ref_t __key_update(key_ref_t key_ref,

ret = key->type->update(key, prep);
if (ret == 0)
/* updating a negative key instantiates it */
clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
/* Updating a negative key positively instantiates it */
mark_key_instantiated(key, 0);

up_write(&key->sem);

Expand Down Expand Up @@ -936,6 +945,16 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
*/
__key_link_end(keyring, &index_key, edit);

key = key_ref_to_ptr(key_ref);
if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) {
ret = wait_for_key_construction(key, true);
if (ret < 0) {
key_ref_put(key_ref);
key_ref = ERR_PTR(ret);
goto error_free_prep;
}
}

key_ref = __key_update(key_ref, &prep);
goto error_free_prep;
}
Expand Down Expand Up @@ -986,8 +1005,8 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)

ret = key->type->update(key, &prep);
if (ret == 0)
/* updating a negative key instantiates it */
clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
/* Updating a negative key positively instantiates it */
mark_key_instantiated(key, 0);

up_write(&key->sem);

Expand Down
Loading

0 comments on commit 494b9ae

Please sign in to comment.