summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-10 18:43:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-10 18:43:43 -0700
commit028db3e290f15ac509084c0fc3b9d021f668f877 (patch)
tree7497244a90100f2464403063f88f83a555da03b3 /security
parente9a83bd2322035ed9d7dcf35753d3f984d76c6a5 (diff)
Revert "Merge tag 'keys-acl-20190703' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs"
This reverts merge 0f75ef6a9cff49ff612f7ce0578bced9d0b38325 (and thus effectively commits 7a1ade847596 ("keys: Provide KEYCTL_GRANT_PERMISSION") 2e12256b9a76 ("keys: Replace uid/gid/perm permissions checking with an ACL") that the merge brought in). It turns out that it breaks booting with an encrypted volume, and Eric biggers reports that it also breaks the fscrypt tests [1] and loading of in-kernel X.509 certificates [2]. The root cause of all the breakage is likely the same, but David Howells is off email so rather than try to work it out it's getting reverted in order to not impact the rest of the merge window. [1] https://lore.kernel.org/lkml/20190710011559.GA7973@sol.localdomain/ [2] https://lore.kernel.org/lkml/20190710013225.GB7973@sol.localdomain/ Link: https://lore.kernel.org/lkml/CAHk-=wjxoeMJfeBahnWH=9zShKp2bsVy527vo3_y8HfOdhwAAw@mail.gmail.com/ Reported-by: Eric Biggers <ebiggers@kernel.org> Cc: David Howells <dhowells@redhat.com> Cc: James Morris <jmorris@namei.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/digsig.c31
-rw-r--r--security/integrity/digsig_asymmetric.c2
-rw-r--r--security/integrity/evm/evm_crypto.c2
-rw-r--r--security/integrity/ima/ima_mok.c13
-rw-r--r--security/integrity/integrity.h6
-rw-r--r--security/integrity/platform_certs/platform_keyring.c14
-rw-r--r--security/keys/compat.c2
-rw-r--r--security/keys/encrypted-keys/encrypted.c2
-rw-r--r--security/keys/encrypted-keys/masterkey_trusted.c2
-rw-r--r--security/keys/gc.c2
-rw-r--r--security/keys/internal.h16
-rw-r--r--security/keys/key.c29
-rw-r--r--security/keys/keyctl.c104
-rw-r--r--security/keys/keyring.c27
-rw-r--r--security/keys/permission.c361
-rw-r--r--security/keys/persistent.c27
-rw-r--r--security/keys/proc.c22
-rw-r--r--security/keys/process_keys.c86
-rw-r--r--security/keys/request_key.c34
-rw-r--r--security/keys/request_key_auth.c15
-rw-r--r--security/selinux/hooks.c16
-rw-r--r--security/smack/smack_lsm.c3
22 files changed, 187 insertions, 629 deletions
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index f9f3c8ffe786..868ade3e8970 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -47,8 +47,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
if (!keyring[id]) {
keyring[id] =
- request_key(&key_type_keyring, keyring_name[id],
- NULL, NULL);
+ request_key(&key_type_keyring, keyring_name[id], NULL);
if (IS_ERR(keyring[id])) {
int err = PTR_ERR(keyring[id]);
pr_err("no %s keyring: %d\n", keyring_name[id], err);
@@ -71,14 +70,14 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
}
static int __init __integrity_init_keyring(const unsigned int id,
- struct key_acl *acl,
+ key_perm_t perm,
struct key_restriction *restriction)
{
const struct cred *cred = current_cred();
int err = 0;
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
- KGIDT_INIT(0), cred, acl,
+ KGIDT_INIT(0), cred, perm,
KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL);
if (IS_ERR(keyring[id])) {
err = PTR_ERR(keyring[id]);
@@ -96,7 +95,10 @@ static int __init __integrity_init_keyring(const unsigned int id,
int __init integrity_init_keyring(const unsigned int id)
{
struct key_restriction *restriction;
- struct key_acl *acl = &internal_keyring_acl;
+ key_perm_t perm;
+
+ perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW
+ | KEY_USR_READ | KEY_USR_SEARCH;
if (id == INTEGRITY_KEYRING_PLATFORM) {
restriction = NULL;
@@ -111,14 +113,14 @@ int __init integrity_init_keyring(const unsigned int id)
return -ENOMEM;
restriction->check = restrict_link_to_ima;
- acl = &internal_writable_keyring_acl;
+ perm |= KEY_USR_WRITE;
out:
- return __integrity_init_keyring(id, acl, restriction);
+ return __integrity_init_keyring(id, perm, restriction);
}
-static int __init integrity_add_key(const unsigned int id, const void *data,
- off_t size, struct key_acl *acl)
+int __init integrity_add_key(const unsigned int id, const void *data,
+ off_t size, key_perm_t perm)
{
key_ref_t key;
int rc = 0;
@@ -127,7 +129,7 @@ static int __init integrity_add_key(const unsigned int id, const void *data,
return -EINVAL;
key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric",
- NULL, data, size, acl ?: &internal_key_acl,
+ NULL, data, size, perm,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
@@ -147,6 +149,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
void *data;
loff_t size;
int rc;
+ key_perm_t perm;
rc = kernel_read_file_from_path(path, &data, &size, 0,
READING_X509_CERTIFICATE);
@@ -155,19 +158,21 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
return rc;
}
+ perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ;
+
pr_info("Loading X.509 certificate: %s\n", path);
- rc = integrity_add_key(id, data, size, NULL);
+ rc = integrity_add_key(id, (const void *)data, size, perm);
vfree(data);
return rc;
}
int __init integrity_load_cert(const unsigned int id, const char *source,
- const void *data, size_t len, struct key_acl *acl)
+ const void *data, size_t len, key_perm_t perm)
{
if (!data)
return -EINVAL;
pr_info("Loading X.509 certificate: %s\n", source);
- return integrity_add_key(id, data, len, acl);
+ return integrity_add_key(id, data, len, perm);
}
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index a29df775fdd8..55aec161d0e1 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -53,7 +53,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
else
key = key_ref_to_ptr(kref);
} else {
- key = request_key(&key_type_asymmetric, name, NULL, NULL);
+ key = request_key(&key_type_asymmetric, name, NULL);
}
if (IS_ERR(key)) {
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 466eebd3b4aa..d485f6fc908e 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -356,7 +356,7 @@ int evm_init_key(void)
struct encrypted_key_payload *ekp;
int rc;
- evm_key = request_key(&key_type_encrypted, EVMKEY, NULL, NULL);
+ evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
if (IS_ERR(evm_key))
return -ENOENT;
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index b52ae1476ec3..36cadadbfba4 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -16,15 +16,6 @@
#include <keys/system_keyring.h>
-static struct key_acl integrity_blacklist_keyring_acl = {
- .usage = REFCOUNT_INIT(1),
- .nr_ace = 2,
- .aces = {
- KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE),
- KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | KEY_ACE_SEARCH),
- }
-};
-
struct key *ima_blacklist_keyring;
/*
@@ -44,7 +35,9 @@ __init int ima_mok_init(void)
ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
- &integrity_blacklist_keyring_acl,
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ |
+ KEY_USR_WRITE | KEY_USR_SEARCH,
KEY_ALLOC_NOT_IN_QUOTA,
restriction, NULL);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 875c6a7a5af1..ed12d8e13d04 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -12,8 +12,6 @@
#include <linux/key.h>
#include <linux/audit.h>
-struct key_acl;
-
/* iint action cache flags */
#define IMA_MEASURE 0x00000001
#define IMA_MEASURED 0x00000002
@@ -157,7 +155,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
int __init integrity_init_keyring(const unsigned int id);
int __init integrity_load_x509(const unsigned int id, const char *path);
int __init integrity_load_cert(const unsigned int id, const char *source,
- const void *data, size_t len, struct key_acl *acl);
+ const void *data, size_t len, key_perm_t perm);
#else
static inline int integrity_digsig_verify(const unsigned int id,
@@ -175,7 +173,7 @@ static inline int integrity_init_keyring(const unsigned int id)
static inline int __init integrity_load_cert(const unsigned int id,
const char *source,
const void *data, size_t len,
- struct key_acl *acl)
+ key_perm_t perm)
{
return 0;
}
diff --git a/security/integrity/platform_certs/platform_keyring.c b/security/integrity/platform_certs/platform_keyring.c
index 7646e35f2d91..bcafd7387729 100644
--- a/security/integrity/platform_certs/platform_keyring.c
+++ b/security/integrity/platform_certs/platform_keyring.c
@@ -14,15 +14,6 @@
#include <linux/slab.h>
#include "../integrity.h"
-static struct key_acl platform_key_acl = {
- .usage = REFCOUNT_INIT(1),
- .nr_ace = 2,
- .aces = {
- KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_READ),
- KEY_OWNER_ACE(KEY_ACE_VIEW),
- }
-};
-
/**
* add_to_platform_keyring - Add to platform keyring without validation.
* @source: Source of key
@@ -35,10 +26,13 @@ static struct key_acl platform_key_acl = {
void __init add_to_platform_keyring(const char *source, const void *data,
size_t len)
{
+ key_perm_t perm;
int rc;
+ perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW;
+
rc = integrity_load_cert(INTEGRITY_KEYRING_PLATFORM, source, data, len,
- &platform_key_acl);
+ perm);
if (rc)
pr_info("Error adding keys to platform keyring %s\n", source);
}
diff --git a/security/keys/compat.c b/security/keys/compat.c
index b0e59546e7bd..9bcc404131aa 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -157,8 +157,6 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
case KEYCTL_MOVE:
return keyctl_keyring_move(arg2, arg3, arg4, arg5);
- case KEYCTL_GRANT_PERMISSION:
- return keyctl_grant_permission(arg2, arg3, arg4, arg5);
case KEYCTL_CAPABILITIES:
return keyctl_capabilities(compat_ptr(arg2), arg3);
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 9df560e477c2..60720f58cbe0 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -304,7 +304,7 @@ static struct key *request_user_key(const char *master_desc, const u8 **master_k
const struct user_key_payload *upayload;
struct key *ukey;
- ukey = request_key(&key_type_user, master_desc, NULL, NULL);
+ ukey = request_key(&key_type_user, master_desc, NULL);
if (IS_ERR(ukey))
goto error;
diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c
index d649f2f29475..c68528aa49c6 100644
--- a/security/keys/encrypted-keys/masterkey_trusted.c
+++ b/security/keys/encrypted-keys/masterkey_trusted.c
@@ -30,7 +30,7 @@ struct key *request_trusted_key(const char *trusted_desc,
struct trusted_key_payload *tpayload;
struct key *tkey;
- tkey = request_key(&key_type_trusted, trusted_desc, NULL, NULL);
+ tkey = request_key(&key_type_trusted, trusted_desc, NULL);
if (IS_ERR(tkey))
goto error;
diff --git a/security/keys/gc.c b/security/keys/gc.c
index 48c3e124c272..671dd730ecfc 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -151,7 +151,6 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
key_user_put(key->user);
key_put_tag(key->domain_tag);
- key_put_acl(rcu_access_pointer(key->acl));
kfree(key->description);
memzero_explicit(key, sizeof(*key));
@@ -221,6 +220,7 @@ continue_scanning:
if (key->type == key_gc_dead_keytype) {
gc_state |= KEY_GC_FOUND_DEAD_KEY;
set_bit(KEY_FLAG_DEAD, &key->flags);
+ key->perm = 0;
goto skip_dead_key;
} else if (key->type == &key_type_keyring &&
key->restrict_link) {
diff --git a/security/keys/internal.h b/security/keys/internal.h
index e0c5bb8b1685..c039373488bd 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -84,11 +84,8 @@ extern struct rb_root key_serial_tree;
extern spinlock_t key_serial_lock;
extern struct mutex key_construction_mutex;
extern wait_queue_head_t request_key_conswq;
-extern struct key_acl default_key_acl;
-extern struct key_acl joinable_keyring_acl;
extern void key_set_index_key(struct keyring_index_key *index_key);
-
extern struct key_type *key_type_lookup(const char *type);
extern void key_type_put(struct key_type *ktype);
@@ -159,7 +156,6 @@ extern struct key *request_key_and_link(struct key_type *type,
const void *callout_info,
size_t callout_len,
void *aux,
- struct key_acl *acl,
struct key *dest_keyring,
unsigned long flags);
@@ -183,10 +179,7 @@ extern void key_gc_keytype(struct key_type *ktype);
extern int key_task_permission(const key_ref_t key_ref,
const struct cred *cred,
- u32 desired_perm);
-extern unsigned int key_acl_to_perm(const struct key_acl *acl);
-extern long key_set_acl(struct key *key, struct key_acl *acl);
-extern void key_put_acl(struct key_acl *acl);
+ key_perm_t perm);
/*
* Check to see whether permission is granted to use a key in the desired way.
@@ -233,7 +226,7 @@ extern long keyctl_keyring_search(key_serial_t, const char __user *,
const char __user *, key_serial_t);
extern long keyctl_read_key(key_serial_t, char __user *, size_t);
extern long keyctl_chown_key(key_serial_t, uid_t, gid_t);
-extern long keyctl_setperm_key(key_serial_t, unsigned int);
+extern long keyctl_setperm_key(key_serial_t, key_perm_t);
extern long keyctl_instantiate_key(key_serial_t, const void __user *,
size_t, key_serial_t);
extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t);
@@ -338,11 +331,6 @@ static inline long keyctl_pkey_e_d_s(int op,
extern long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen);
-extern long keyctl_grant_permission(key_serial_t keyid,
- enum key_ace_subject_type type,
- unsigned int subject,
- unsigned int perm);
-
/*
* Debugging key validation
*/
diff --git a/security/keys/key.c b/security/keys/key.c
index 519211a996e7..764f4c57913e 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -195,7 +195,7 @@ serial_exists:
* @uid: The owner of the new key.
* @gid: The group ID for the new key's group permissions.
* @cred: The credentials specifying UID namespace.
- * @acl: The ACL to attach to the new key.
+ * @perm: The permissions mask of the new key.
* @flags: Flags specifying quota properties.
* @restrict_link: Optional link restriction for new keyrings.
*
@@ -223,7 +223,7 @@ serial_exists:
*/
struct key *key_alloc(struct key_type *type, const char *desc,
kuid_t uid, kgid_t gid, const struct cred *cred,
- struct key_acl *acl, unsigned long flags,
+ key_perm_t perm, unsigned long flags,
struct key_restriction *restrict_link)
{
struct key_user *user = NULL;
@@ -246,9 +246,6 @@ struct key *key_alloc(struct key_type *type, const char *desc,
desclen = strlen(desc);
quotalen = desclen + 1 + type->def_datalen;
- if (!acl)
- acl = &default_key_acl;
-
/* get hold of the key tracking for this user */
user = key_user_lookup(uid);
if (!user)
@@ -295,8 +292,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->datalen = type->def_datalen;
key->uid = uid;
key->gid = gid;
- refcount_inc(&acl->usage);
- rcu_assign_pointer(key->acl, acl);
+ key->perm = perm;
key->restrict_link = restrict_link;
key->last_used_at = ktime_get_real_seconds();
@@ -791,7 +787,7 @@ error:
* @description: The searchable description for the key.
* @payload: The data to use to instantiate or update the key.
* @plen: The length of @payload.
- * @acl: The ACL to attach if a key is created.
+ * @perm: The permissions mask for a new key.
* @flags: The quota flags for a new key.
*
* Search the destination keyring for a key of the same description and if one
@@ -814,7 +810,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
const char *description,
const void *payload,
size_t plen,
- struct key_acl *acl,
+ key_perm_t perm,
unsigned long flags)
{
struct keyring_index_key index_key = {
@@ -911,9 +907,22 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
goto found_matching_key;
}
+ /* 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;
+
+ if (index_key.type->read)
+ perm |= KEY_POS_READ;
+
+ if (index_key.type == &key_type_keyring ||
+ index_key.type->update)
+ perm |= KEY_POS_WRITE;
+ }
+
/* allocate a new key */
key = key_alloc(index_key.type, index_key.description,
- cred->fsuid, cred->fsgid, cred, acl, flags, NULL);
+ cred->fsuid, cred->fsgid, cred, perm, flags, NULL);
if (IS_ERR(key)) {
key_ref = ERR_CAST(key);
goto error_link_end;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index c2dd66d556d4..9b898c969558 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -37,8 +37,7 @@ static const unsigned char keyrings_capabilities[2] = {
KEYCTL_CAPS0_MOVE
),
[1] = (KEYCTL_CAPS1_NS_KEYRING_NAME |
- KEYCTL_CAPS1_NS_KEY_TAG |
- KEYCTL_CAPS1_ACL_ALTERABLE),
+ KEYCTL_CAPS1_NS_KEY_TAG),
};
static int key_get_type_from_user(char *type,
@@ -131,7 +130,8 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
/* create or update the requested key and add it to the target
* keyring */
key_ref = key_create_or_update(keyring_ref, type, description,
- payload, plen, NULL, KEY_ALLOC_IN_QUOTA);
+ payload, plen, KEY_PERM_UNDEF,
+ KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key_ref)) {
ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref);
@@ -221,8 +221,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
/* do the search */
key = request_key_and_link(ktype, description, NULL, callout_info,
- callout_len, NULL, NULL,
- key_ref_to_ptr(dest_ref),
+ callout_len, NULL, key_ref_to_ptr(dest_ref),
KEY_ALLOC_IN_QUOTA);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
@@ -384,10 +383,16 @@ long keyctl_revoke_key(key_serial_t id)
struct key *key;
long ret;
- key_ref = lookup_user_key(id, 0, KEY_NEED_REVOKE);
+ key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
- goto error;
+ if (ret != -EACCES)
+ goto error;
+ key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR);
+ if (IS_ERR(key_ref)) {
+ ret = PTR_ERR(key_ref);
+ goto error;
+ }
}
key = key_ref_to_ptr(key_ref);
@@ -421,7 +426,7 @@ long keyctl_invalidate_key(key_serial_t id)
kenter("%d", id);
- key_ref = lookup_user_key(id, 0, KEY_NEED_INVAL);
+ key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
@@ -466,7 +471,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
struct key *keyring;
long ret;
- keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_CLEAR);
+ keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring_ref);
@@ -641,7 +646,6 @@ long keyctl_describe_key(key_serial_t keyid,
size_t buflen)
{
struct key *key, *instkey;
- unsigned int perm;
key_ref_t key_ref;
char *infobuf;
long ret;
@@ -671,10 +675,6 @@ okay:
key = key_ref_to_ptr(key_ref);
desclen = strlen(key->description);
- rcu_read_lock();
- perm = key_acl_to_perm(rcu_dereference(key->acl));
- rcu_read_unlock();
-
/* calculate how much information we're going to return */
ret = -ENOMEM;
infobuf = kasprintf(GFP_KERNEL,
@@ -682,7 +682,7 @@ okay:
key->type->name,
from_kuid_munged(current_user_ns(), key->uid),
from_kgid_munged(current_user_ns(), key->gid),
- perm);
+ key->perm);
if (!infobuf)
goto error2;
infolen = strlen(infobuf);
@@ -899,7 +899,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
goto error;
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
- KEY_NEED_SETSEC);
+ KEY_NEED_SETATTR);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error;
@@ -994,25 +994,18 @@ quota_overrun:
* the key need not be fully instantiated yet. If the caller does not have
* sysadmin capability, it may only change the permission on keys that it owns.
*/
-long keyctl_setperm_key(key_serial_t id, unsigned int perm)
+long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
{
- struct key_acl *acl;
struct key *key;
key_ref_t key_ref;
long ret;
- int nr, i, j;
+ ret = -EINVAL;
if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
- return -EINVAL;
-
- nr = 0;
- if (perm & KEY_POS_ALL) nr++;
- if (perm & KEY_USR_ALL) nr++;
- if (perm & KEY_GRP_ALL) nr++;
- if (perm & KEY_OTH_ALL) nr++;
+ goto error;
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
- KEY_NEED_SETSEC);
+ KEY_NEED_SETATTR);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error;
@@ -1020,45 +1013,17 @@ long keyctl_setperm_key(key_serial_t id, unsigned int perm)
key = key_ref_to_ptr(key_ref);
- ret = -EOPNOTSUPP;
- if (test_bit(KEY_FLAG_HAS_ACL, &key->flags))
- goto error_key;
+ /* make the changes with the locks held to prevent chown/chmod races */
+ ret = -EACCES;
+ down_write(&key->sem);
- ret = -ENOMEM;
- acl = kzalloc(struct_size(acl, aces, nr), GFP_KERNEL);
- if (!acl)
- goto error_key;
-
- refcount_set(&acl->usage, 1);
- acl->nr_ace = nr;
- j = 0;
- for (i = 0; i < 4; i++) {
- struct key_ace *ace = &acl->aces[j];
- unsigned int subset = (perm >> (i * 8)) & KEY_OTH_ALL;
-
- if (!subset)
- continue;
- ace->type = KEY_ACE_SUBJ_STANDARD;
- ace->subject_id = KEY_ACE_EVERYONE + i;
- ace->perm = subset;
- if (subset & (KEY_OTH_WRITE | KEY_OTH_SETATTR))
- ace->perm |= KEY_ACE_REVOKE;
- if (subset & KEY_OTH_SEARCH)
- ace->perm |= KEY_ACE_INVAL;
- if (key->type == &key_type_keyring) {
- if (subset & KEY_OTH_SEARCH)
- ace->perm |= KEY_ACE_JOIN;
- if (subset & KEY_OTH_WRITE)
- ace->perm |= KEY_ACE_CLEAR;
- }
- j++;
+ /* if we're not the sysadmin, we can only change a key that we own */
+ if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) {
+ key->perm = perm;
+ ret = 0;
}
- /* make the changes with the locks held to prevent chown/chmod races */
- down_write(&key->sem);
- ret = key_set_acl(key, acl);
up_write(&key->sem);
-error_key:
key_put(key);
error:
return ret;
@@ -1423,7 +1388,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
long ret;
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
- KEY_NEED_SETSEC);
+ KEY_NEED_SETATTR);
if (IS_ERR(key_ref)) {
/* setting the timeout on a key under construction is permitted
* if we have the authorisation token handy */
@@ -1574,7 +1539,7 @@ long keyctl_get_security(key_serial_t keyid,
* Attempt to install the calling process's session keyring on the process's
* parent process.
*
- * The keyring must exist and must grant the caller JOIN permission, and the
+ * The keyring must exist and must grant the caller LINK permission, and the
* parent process must be single-threaded and must have the same effective
* ownership as this process and mustn't be SUID/SGID.
*
@@ -1591,7 +1556,7 @@ long keyctl_session_to_parent(void)
struct cred *cred;
int ret;
- keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_JOIN);
+ keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_LINK);
if (IS_ERR(keyring_r))
return PTR_ERR(keyring_r);
@@ -1693,7 +1658,7 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type,
char *restriction = NULL;
long ret;
- key_ref = lookup_user_key(id, 0, KEY_NEED_SETSEC);
+ key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR);
if (IS_ERR(key_ref))
return PTR_ERR(key_ref);
@@ -1799,7 +1764,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
case KEYCTL_SETPERM:
return keyctl_setperm_key((key_serial_t) arg2,
- (unsigned int)arg3);
+ (key_perm_t) arg3);
case KEYCTL_INSTANTIATE:
return keyctl_instantiate_key((key_serial_t) arg2,
@@ -1888,11 +1853,6 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
(key_serial_t)arg3,
(key_serial_t)arg4,
(unsigned int)arg5);
- case KEYCTL_GRANT_PERMISSION:
- return keyctl_grant_permission((key_serial_t)arg2,
- (enum key_ace_subject_type)arg3,
- (unsigned int)arg4,
- (unsigned int)arg5);
case KEYCTL_CAPABILITIES:
return keyctl_capabilities((unsigned char __user *)arg2, (size_t)arg3);
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 3b5458f23a95..febf36c6ddc5 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -515,19 +515,11 @@ static long keyring_read(const struct key *keyring,
return ret;
}
-/**
- * keyring_alloc - Allocate a keyring and link into the destination
- * @description: The key description to allow the key to be searched out.
- * @uid: The owner of the new key.
- * @gid: The group ID for the new key's group permissions.
- * @cred: The credentials specifying UID namespace.
- * @acl: The ACL to attach to the new key.
- * @flags: Flags specifying quota properties.
- * @restrict_link: Optional link restriction for new keyrings.
- * @dest: Destination keyring.
+/*
+ * Allocate a keyring and link into the destination keyring.
*/
struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
- const struct cred *cred, struct key_acl *acl,
+ const struct cred *cred, key_perm_t perm,
unsigned long flags,
struct key_restriction *restrict_link,
struct key *dest)
@@ -536,7 +528,7 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
int ret;
keyring = key_alloc(&key_type_keyring, description,
- uid, gid, cred, acl, flags, restrict_link);
+ uid, gid, cred, perm, flags, restrict_link);
if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
if (ret < 0) {
@@ -1140,11 +1132,10 @@ found:
/*
* Find a keyring with the specified name.
*
- * Only keyrings that have nonzero refcount, are not revoked, and are owned by
- * a user in the current user namespace are considered. If @uid_keyring is
- * %true, the keyring additionally must have been allocated as a user or user
- * session keyring; otherwise, it must grant JOIN permission directly to the
- * caller (ie. not through possession).
+ * Only keyrings that have nonzero refcount, are not revoked, and are owned by a
+ * user in the current user namespace are considered. If @uid_keyring is %true,
+ * the keyring additionally must have been allocated as a user or user session
+ * keyring; otherwise, it must grant Search permission directly to the caller.
*
* Returns a pointer to the keyring with the keyring's refcount having being
* incremented on success. -ENOKEY is returned if a key could not be found.
@@ -1178,7 +1169,7 @@ struct key *find_keyring_by_name(const char *name, bool uid_keyring)
continue;
} else {
if (key_permission(make_key_ref(keyring, 0),
- KEY_NEED_JOIN) < 0)
+ KEY_NEED_SEARCH) < 0)
continue;
}
diff --git a/security/keys/permission.c b/security/keys/permission.c
index fd8a5dc6910a..085f907b64ac 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -7,67 +7,13 @@
#include <linux/export.h>
#include <linux/security.h>
-#include <linux/user_namespace.h>
-#include <linux/uaccess.h>
#include "internal.h"
-struct key_acl default_key_acl = {
- .usage = REFCOUNT_INIT(1),
- .nr_ace = 2,
- .possessor_viewable = true,
- .aces = {
- KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN),
- KEY_OWNER_ACE(KEY_ACE_VIEW),
- }
-};
-EXPORT_SYMBOL(default_key_acl);
-
-struct key_acl joinable_keyring_acl = {
- .usage = REFCOUNT_INIT(1),
- .nr_ace = 2,
- .possessor_viewable = true,
- .aces = {
- KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN),
- KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_LINK | KEY_ACE_JOIN),
- }
-};
-EXPORT_SYMBOL(joinable_keyring_acl);
-
-struct key_acl internal_key_acl = {
- .usage = REFCOUNT_INIT(1),
- .nr_ace = 2,
- .aces = {
- KEY_POSSESSOR_ACE(KEY_ACE_SEARCH),
- KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH),
- }
-};
-EXPORT_SYMBOL(internal_key_acl);
-
-struct key_acl internal_keyring_acl = {
- .usage = REFCOUNT_INIT(1),
- .nr_ace = 2,
- .aces = {
- KEY_POSSESSOR_ACE(KEY_ACE_SEARCH),
- KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH),
- }
-};
-EXPORT_SYMBOL(internal_keyring_acl);
-
-struct key_acl internal_writable_keyring_acl = {
- .usage = REFCOUNT_INIT(1),
- .nr_ace = 2,
- .aces = {
- KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE),
- KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | KEY_ACE_SEARCH),
- }