diff options
45 files changed, 857 insertions, 324 deletions
diff --git a/Documentation/security/keys/core.rst b/Documentation/security/keys/core.rst index 0e74f372e58c..1b3c907980ad 100644 --- a/Documentation/security/keys/core.rst +++ b/Documentation/security/keys/core.rst @@ -57,9 +57,9 @@ Each key has a number of attributes: type provides an operation to perform a match between the description on a key and a criterion string. - * Each key has an owner user ID, a group ID and a permissions mask. These - are used to control what a process may do to a key from userspace, and - whether a kernel service will be able to find the key. + * Each key has an owner user ID, a group ID and an ACL. These are used to + control what a process may do to a key from userspace, and whether a + kernel service will be able to find the key. * Each key can be set to expire at a specific time by the key type's instantiation function. Keys can also be immortal. @@ -198,43 +198,110 @@ The key service provides a number of features besides keys: Key Access Permissions ====================== -Keys have an owner user ID, a group access ID, and a permissions mask. The mask -has up to eight bits each for possessor, user, group and other access. Only -six of each set of eight bits are defined. These permissions granted are: +Keys have an owner user ID, a group ID and an ACL. The ACL is made up of a +sequence of ACEs that each contain three elements: - * View + * The type of subject. + * The subject. - This permits a key or keyring's attributes to be viewed - including key - type and description. + These two together indicate the subject to whom the permits are granted. + The type can be one of: - * Read + * ``KEY_ACE_SUBJ_STANDARD`` - This permits a key's payload to be viewed or a keyring's list of linked - keys. + The subject is a standard 'macro' type. The subject can be one of: + + * ``KEY_ACE_EVERYONE`` + + The permits are granted to everyone. It replaces the old 'other' + type on the assumption that you wouldn't grant a permission to other + that you you wouldn't grant to everyone else. + + * ``KEY_ACE_OWNER`` + + The permits are granted to the owner of the key (key->uid). + + * ``KEY_ACE_GROUP`` + + The permits are granted to the key's group (key->gid). + + * ``KEY_ACE_POSSESSOR`` + + The permits are granted to anyone who possesses the key. + + * The set of permits granted to the subject. These include: + + * ``KEY_ACE_VIEW`` + + This permits a key or keyring's attributes to be viewed - including the + key type and description. + + * ``KEY_ACE_READ`` + + This permits a key's payload to be viewed or a keyring's list of linked + keys. - * Write + * ``KEY_ACE_WRITE`` - This permits a key's payload to be instantiated or updated, or it allows a - link to be added to or removed from a keyring. + This permits a key's payload to be instantiated or updated, or it allows + a link to be added to or removed from a keyring. - * Search + * ``KEY_ACE_SEARCH`` - This permits keyrings to be searched and keys to be found. Searches can - only recurse into nested keyrings that have search permission set. + This permits keyrings to be searched and keys to be found. Searches can + only recurse into nested keyrings that have search permission set. - * Link + * ``KEY_ACE_LINK`` - This permits a key or keyring to be linked to. To create a link from a - keyring to a key, a process must have Write permission on the keyring and - Link permission on the key. + This permits a key or keyring to be linked to. To create a link from a + keyring to a key, a process must have Write permission on the keyring + and Link permission on the key. - * Set Attribute + * ``KEY_ACE_SET_SECURITY`` - This permits a key's UID, GID and permissions mask to be changed. + This permits a key's UID, GID and permissions mask to be changed. + + * ``KEY_ACE_INVAL`` + + This permits a key to be invalidated with KEYCTL_INVALIDATE. + + * ``KEY_ACE_REVOKE`` + + This permits a key to be revoked with KEYCTL_REVOKE. + + * ``KEY_ACE_JOIN`` + + This permits a keyring to be joined as a session by + KEYCTL_JOIN_SESSION_KEYRING or KEYCTL_SESSION_TO_PARENT. + + * ``KEY_ACE_CLEAR`` + + This permits a keyring to be cleared. For changing the ownership, group ID or permissions mask, being the owner of the key or having the sysadmin capability is sufficient. +The legacy KEYCTL_SETPERM and KEYCTL_DESCRIBE functions can only see/generate +View, Read, Write, Search, Link and SetAttr permits, and do this for each of +possessor, user, group and other permission sets as a 32-bit flag mask. These +will be approximated/inferred: + + SETPERM Permit Implied ACE Permit + =============== ======================= + Search Inval, Join + Write Revoke, Clear + Setattr Set Security, Revoke + + ACE Permit Described as + =============== ======================= + Inval Search + Join Search + Revoke Write (unless Setattr) + Clear write + Set Security Setattr + +'Other' will be approximated as/inferred from the 'Everyone' subject. + SELinux Support =============== @@ -1084,7 +1151,8 @@ payload contents" for more information. struct key *request_key(const struct key_type *type, const char *description, - const char *callout_info); + const char *callout_info, + struct key_acl *acl); This is used to request a key or keyring with a description that matches the description specified according to the key type's match_preparse() @@ -1099,6 +1167,8 @@ payload contents" for more information. If successful, the key will have been attached to the default keyring for implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING. + If a key is created, it will be given the specified ACL. + See also Documentation/security/keys/request-key.rst. @@ -1107,7 +1177,8 @@ payload contents" for more information. struct key *request_key_tag(const struct key_type *type, const char *description, struct key_tag *domain_tag, - const char *callout_info); + const char *callout_info, + struct key_acl *acl); This is identical to request_key(), except that a domain tag may be specifies that causes search algorithm to only match keys matching that @@ -1122,7 +1193,8 @@ payload contents" for more information. struct key_tag *domain_tag, const void *callout_info, size_t callout_len, - void *aux); + void *aux, + struct key_acl *acl); This is identical to request_key_tag(), except that the auxiliary data is passed to the key_type->request_key() op if it exists, and the @@ -1195,7 +1267,7 @@ payload contents" for more information. struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, const struct cred *cred, - key_perm_t perm, + struct key_acl *acl, struct key_restriction *restrict_link, unsigned long flags, struct key *dest); diff --git a/Documentation/security/keys/request-key.rst b/Documentation/security/keys/request-key.rst index 35f2296b704a..f356fd06c8d5 100644 --- a/Documentation/security/keys/request-key.rst +++ b/Documentation/security/keys/request-key.rst @@ -11,14 +11,16 @@ The process starts by either the kernel requesting a service by calling struct key *request_key(const struct key_type *type, const char *description, - const char *callout_info); + const char *callout_info, + struct key_acl *acl); or:: struct key *request_key_tag(const struct key_type *type, const char *description, const struct key_tag *domain_tag, - const char *callout_info); + const char *callout_info, + struct key_acl *acl); or:: @@ -27,7 +29,8 @@ or:: const struct key_tag *domain_tag, const char *callout_info, size_t callout_len, - void *aux); + void *aux, + struct key_acl *acl); or:: diff --git a/certs/blacklist.c b/certs/blacklist.c index 181cb7fa9540..39de9d68b21e 100644 --- a/certs/blacklist.c +++ b/certs/blacklist.c @@ -93,8 +93,7 @@ int mark_hash_blacklisted(const char *hash) hash, NULL, 0, - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW), + &internal_key_acl, KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN); if (IS_ERR(key)) { @@ -153,9 +152,7 @@ static int __init blacklist_init(void) keyring_alloc(".blacklist", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), - (KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ | - KEY_USR_SEARCH, + &internal_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA | KEY_FLAG_KEEP, NULL, NULL); diff --git a/certs/system_keyring.c b/certs/system_keyring.c index c05c29ae4d5d..2873a4ce2828 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -103,9 +103,7 @@ static __init int system_trusted_keyring_init(void) builtin_trusted_keys = keyring_alloc(".builtin_trusted_keys", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH), - KEY_ALLOC_NOT_IN_QUOTA, + &internal_key_acl, KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); if (IS_ERR(builtin_trusted_keys)) panic("Can't allocate builtin trusted keyring\n"); @@ -114,10 +112,7 @@ static __init int system_trusted_keyring_init(void) secondary_trusted_keys = keyring_alloc(".secondary_trusted_keys", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH | - KEY_USR_WRITE), - KEY_ALLOC_NOT_IN_QUOTA, + &internal_writable_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA, get_builtin_and_secondary_restriction(), NULL); if (IS_ERR(secondary_trusted_keys)) @@ -167,8 +162,7 @@ static __init int load_system_certificate_list(void) NULL, p, plen, - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ), + &internal_key_acl, KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN | KEY_ALLOC_BYPASS_RESTRICTION); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 1b16d34bb785..0fd3ca9bfe54 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2035,7 +2035,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string return -ENOMEM; key = request_key(key_string[0] == 'l' ? &key_type_logon : &key_type_user, - key_desc + 1, NULL); + key_desc + 1, NULL, NULL); if (IS_ERR(key)) { kzfree(new_key_string); return PTR_ERR(key); diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index a570f2263a42..99a5708b37e3 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -55,7 +55,7 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) struct device *dev = &nvdimm->dev; sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id); - key = request_key(&key_type_encrypted, desc, ""); + key = request_key(&key_type_encrypted, desc, "", NULL); if (IS_ERR(key)) { if (PTR_ERR(key) == -ENOKEY) dev_dbg(dev, "request_key() found no key\n"); diff --git a/fs/afs/security.c b/fs/afs/security.c index 5d8ece98561e..3185898237b2 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -32,7 +32,7 @@ struct key *afs_request_key(struct afs_cell *cell) _debug("key %s", cell->anonymous_key->description); key = request_key(&key_type_rxrpc, cell->anonymous_key->description, - NULL); + NULL, NULL); if (IS_ERR(key)) { if (PTR_ERR(key) != -ENOKEY) { _leave(" = %ld", PTR_ERR(key)); diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 7f01c6e60791..d1b439ad0f1a 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -32,6 +32,25 @@ #include "cifsproto.h" static const struct cred *spnego_cred; +static struct key_acl cifs_spnego_key_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .possessor_viewable = true, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_SEARCH | KEY_ACE_READ), + KEY_OWNER_ACE(KEY_ACE_VIEW), + } +}; + +static struct key_acl cifs_spnego_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_CLEAR), + } +}; + /* create a new cifs key */ static int cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep) @@ -170,7 +189,8 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo) cifs_dbg(FYI, "key description = %s\n", description); saved_cred = override_creds(spnego_cred); - spnego_key = request_key(&cifs_spnego_key_type, description, ""); + spnego_key = request_key(&cifs_spnego_key_type, description, "", + &cifs_spnego_key_acl); revert_creds(saved_cred); #ifdef CONFIG_CIFS_DEBUG2 @@ -207,8 +227,7 @@ init_cifs_spnego(void) keyring = keyring_alloc(".cifs_spnego", GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, - (KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ, + &cifs_spnego_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 1d377b7f2860..78eed72f3af0 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -33,6 +33,25 @@ #include "cifsproto.h" #include "cifs_debug.h" +static struct key_acl cifs_idmap_key_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .possessor_viewable = true, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_SEARCH | KEY_ACE_READ), + KEY_OWNER_ACE(KEY_ACE_VIEW), + } +}; + +static struct key_acl cifs_idmap_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), + } +}; + /* security id for everyone/world system group */ static const struct cifs_sid sid_everyone = { 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; @@ -298,7 +317,8 @@ id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid) rc = 0; saved_cred = override_creds(root_cred); - sidkey = request_key(&cifs_idmap_key_type, desc, ""); + sidkey = request_key(&cifs_idmap_key_type, desc, "", + &cifs_idmap_key_acl); if (IS_ERR(sidkey)) { rc = -EINVAL; cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n", @@ -403,7 +423,8 @@ try_upcall_to_get_id: return -ENOMEM; saved_cred = override_creds(root_cred); - sidkey = request_key(&cifs_idmap_key_type, sidstr, ""); + sidkey = request_key(&cifs_idmap_key_type, sidstr, "", + &cifs_idmap_key_acl); if (IS_ERR(sidkey)) { rc = -EINVAL; cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n", @@ -481,8 +502,7 @@ init_cifs_idmap(void) keyring = keyring_alloc(".cifs_idmap", GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, - (KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ, + &cifs_idmap_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8c4121da624e..6e50d3e87948 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2990,7 +2990,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) } cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc); - key = request_key(&key_type_logon, desc, ""); + key = request_key(&key_type_logon, desc, "", NULL); if (IS_ERR(key)) { if (!ses->domainName) { cifs_dbg(FYI, "domainName is NULL\n"); @@ -3001,7 +3001,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) /* didn't work, try to find a domain key */ sprintf(desc, "cifs:d:%s", ses->domainName); cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc); - key = request_key(&key_type_logon, desc, ""); + key = request_key(&key_type_logon, desc, "", NULL); if (IS_ERR(key)) { rc = PTR_ERR(key); goto out_err; diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index dcd91a3fbe49..4f85af8ab239 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -92,7 +92,7 @@ find_and_lock_process_key(const char *prefix, if (!description) return ERR_PTR(-ENOMEM); - key = request_key(&key_type_logon, description, NULL); + key = request_key(&key_type_logon, description, NULL, NULL); kfree(description); if (IS_ERR(key)) return key; diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index e74cb2a0b299..6460bd2a4e9d 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -105,7 +105,7 @@ ecryptfs_get_encrypted_key_payload_data(struct key *key) static inline struct key *ecryptfs_get_encrypted_key(char *sig) { - return request_key(&key_type_encrypted, sig, NULL); + return request_key(&key_type_encrypted, sig, NULL, NULL); } #else diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 90fbac5d485b..923a6006ccea 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1624,7 +1624,7 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, { int rc = 0; - (*auth_tok_key) = request_key(&key_type_user, sig, NULL); + (*auth_tok_key) = request_key(&key_type_user, sig, NULL, NULL); if (!(*auth_tok_key) || IS_ERR(*auth_tok_key)) { (*auth_tok_key) = ecryptfs_get_encrypted_key(sig); if (!(*auth_tok_key) || IS_ERR(*auth_tok_key)) { diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index 43e6e28c164f..6a672289e5ec 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c @@ -321,7 +321,7 @@ static void fscache_objlist_config(struct fscache_objlist_data *data) const char *buf; int len; - key = request_key(&key_type_user, "fscache:objlist", NULL); + key = request_key(&key_type_user, "fscache:objlist", NULL, NULL); if (IS_ERR(key)) goto no_config; diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c index 1e7296395d71..69679f4f2e6c 100644 --- a/fs/nfs/nfs4idmap.c +++ b/fs/nfs/nfs4idmap.c @@ -72,6 +72,25 @@ struct idmap { const struct cred *cred; }; +static struct key_acl nfs_idmap_key_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .possessor_viewable = true, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_SEARCH | KEY_ACE_READ), + KEY_OWNER_ACE(KEY_ACE_VIEW), + } +}; + +static struct key_acl nfs_idmap_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), + } +}; + static struct user_namespace *idmap_userns(const struct idmap *idmap) { if (idmap && idmap->cred) @@ -208,8 +227,7 @@ int nfs_idmap_init(void) keyring = keyring_alloc(".id_resolver", GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, - (KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ, + &nfs_idmap_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); @@ -287,11 +305,13 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen, return ERR_PTR(ret); if (!idmap->cred || idmap->cred->user_ns == &init_user_ns) - rkey = request_key(&key_type_id_resolver, desc, ""); + rkey = request_key(&key_type_id_resolver, desc, "", + &nfs_idmap_key_acl); if (IS_ERR(rkey)) { mutex_lock(&idmap->idmap_mutex); rkey = request_key_with_auxdata(&key_type_id_resolver_legacy, - desc, NULL, "", 0, idmap); + desc, NULL, "", 0, idmap, + &nfs_idmap_key_acl); mutex_unlock(&idmap->idmap_mutex); } if (!IS_ERR(rkey)) @@ -320,8 +340,6 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, } rcu_read_lock(); - rkey->perm |= KEY_USR_VIEW; - ret = key_validate(rkey); if (ret < 0) goto out_up; diff --git a/fs/ubifs/auth.c b/fs/ubifs/auth.c index 60f43b93d06e..38718026ad0b 100644 --- a/fs/ubifs/auth.c +++ b/fs/ubifs/auth.c @@ -227,7 +227,7 @@ int ubifs_init_authentication(struct ubifs_info *c) snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", c->auth_hash_name); - keyring_key = request_key(&key_type_logon, c->auth_key_name, NULL); + keyring_key = request_key(&key_type_logon, c->auth_key_name, NULL, NULL); if (IS_ERR(keyring_key)) { ubifs_err(c, "Failed to request key: %ld", diff --git a/include/linux/key.h b/include/linux/key.h index 18d7f62ab6b0..bc4adfd254fe 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -32,49 +32,14 @@ /* key handle serial number */ typedef int32_t key_serial_t; -/* key handle permissions mask */ -typedef uint32_t key_perm_t; - struct key; struct net; #ifdef CONFIG_KEYS -#undef KEY_DEBUGGING +#include <linux/keyctl.h> -#define KEY_POS_VIEW 0x01000000 /* possessor can view a key's attributes */ -#define KEY_POS_READ 0x02000000 /* possessor can read key payload / view keyring */ -#define KEY_POS_WRITE 0x04000000 /* possessor can update key payload / add link to keyring */ -#define KEY_POS_SEARCH 0x08000000 /* possessor can find a key in search / search a keyring */ -#define KEY_POS_LINK 0x10000000 /* possessor can create a link to a key/keyring */ -#define KEY_POS_SETATTR 0x20000000 /* possessor can set key attributes */ -#define KEY_POS_ALL 0x3f000000 - -#define KEY_USR_VIEW 0x00010000 /* user permissions... */ -#define KEY_USR_READ 0x00020000 -#define KEY_USR_WRITE 0x00040000 -#define KEY_USR_SEARCH 0x00080000 -#define KEY_USR_LINK 0x00100000 -#define KEY_USR_SETATTR 0x00200000 -#define KEY_USR_ALL 0x003f0000 - -#define KEY_GRP_VIEW 0x00000100 /* group permissions... */ -#define KEY_GRP_READ 0x00000200 -#define KEY_GRP_WRITE 0x00000400 -#define KEY_GRP_SEARCH 0x00000800 -#define KEY_GRP_LINK 0x00001000 -#define KEY_GRP_SETATTR 0x00002000 -#define KEY_GRP_ALL 0x00003f00 - -#define KEY_OTH_VIEW 0x00000001 /* third party permissions... */ -#define KEY_OTH_READ 0x00000002 -#define KEY_OTH_WRITE 0x00000004 -#define KEY_OTH_SEARCH 0x00000008 -#define KEY_OTH_LINK 0x00000010 -#define KEY_OTH_SETATTR 0x00000020 -#define KEY_OTH_ALL 0x0000003f - -#define KEY_PERM_UNDEF 0xffffffff +#undef KEY_DEBUGGING struct seq_file; struct user_struct; @@ -118,6 +83,36 @@ union key_payload { void *data[4]; }; +struct key_ace { + unsigned int type; + unsigned int perm; + union { + kuid_t uid; + kgid_t gid; + unsigned int subject_id; + }; +}; + +struct key_acl { + refcount_t usage; + unsigned short nr_ace; + bool possessor_viewable; + struct rcu_head rcu; + struct key_ace aces[]; +}; + +#define KEY_POSSESSOR_ACE(perms) { \ + .type = KEY_ACE_SUBJ_STANDARD, \ + .perm = perms, \ + .subject_id = KEY_ACE_POSSESSOR \ + } + +#define KEY_OWNER_ACE(perms) { \ + .type = KEY_ACE_SUBJ_STANDARD, \ + .perm = perms, \ + .subject_id = KEY_ACE_OWNER \ + } + /*****************************************************************************/ /* * key reference with possession attribute handling @@ -184,6 +179,7 @@ struct key { struct rw_semaphore sem; /* change vs change sem */ struct key_user *user; /* owner of this key */ void *security; /* security data for this key */ + struct key_acl __rcu *acl; union { time64_t expiry; /* time at which key expires (or 0) */ time64_t revoked_at; /* time at which key was revoked */ @@ -191,7 +187,6 @@ struct key { time64_t last_used_at; /* last time used for LRU keyring discard */ kuid_t uid; kgid_t gid; - key_perm_t perm; /* access permissions */ unsigned short quotalen; /* length added to quota */ unsigned short datalen; /* payload data length * - may not match RCU dereferenced payload @@ -215,6 +210,7 @@ struct key { #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 */ +#define KEY_FLAG_HAS_ACL 10 /* Set if KEYCTL_SETACL called on key */ /* the key type and key description string * - the desc is used to match a key against search criteria @@ -263,7 +259,7 @@ extern struct key *key_alloc(struct key_type *type, const char *desc, kuid_t uid, kgid_t gid, const struct cred *cred, < |