[PATCH] keys: sort out key quota system

Add the ability for key creation to overrun the user's quota in some
circumstances - notably when a session keyring is created and assigned to a
process that didn't previously have one.

This means it's still possible to log in, should PAM require the creation of a
new session keyring, and fix an overburdened key quota.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
David Howells 2006-06-26 00:24:50 -07:00 committed by Linus Torvalds
parent f116629d03
commit 7e047ef5fe
11 changed files with 85 additions and 51 deletions

View File

@ -248,7 +248,14 @@ extern struct key *key_alloc(struct key_type *type,
const char *desc, const char *desc,
uid_t uid, gid_t gid, uid_t uid, gid_t gid,
struct task_struct *ctx, struct task_struct *ctx,
key_perm_t perm, int not_in_quota); key_perm_t perm,
unsigned long flags);
#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */
#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
extern int key_payload_reserve(struct key *key, size_t datalen); extern int key_payload_reserve(struct key *key, size_t datalen);
extern int key_instantiate_and_link(struct key *key, extern int key_instantiate_and_link(struct key *key,
const void *data, const void *data,
@ -285,7 +292,7 @@ extern key_ref_t key_create_or_update(key_ref_t keyring,
const char *description, const char *description,
const void *payload, const void *payload,
size_t plen, size_t plen,
int not_in_quota); unsigned long flags);
extern int key_update(key_ref_t key, extern int key_update(key_ref_t key,
const void *payload, const void *payload,
@ -299,7 +306,7 @@ extern int key_unlink(struct key *keyring,
extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
struct task_struct *ctx, struct task_struct *ctx,
int not_in_quota, unsigned long flags,
struct key *dest); struct key *dest);
extern int keyring_clear(struct key *keyring); extern int keyring_clear(struct key *keyring);

View File

@ -862,6 +862,7 @@ struct swap_info_struct;
* Permit allocation of a key and assign security data. Note that key does * Permit allocation of a key and assign security data. Note that key does
* not have a serial number assigned at this point. * not have a serial number assigned at this point.
* @key points to the key. * @key points to the key.
* @flags is the allocation flags
* Return 0 if permission is granted, -ve error otherwise. * Return 0 if permission is granted, -ve error otherwise.
* @key_free: * @key_free:
* Notification of destruction; free security data. * Notification of destruction; free security data.
@ -1324,7 +1325,7 @@ struct security_operations {
/* key management security hooks */ /* key management security hooks */
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
int (*key_alloc)(struct key *key, struct task_struct *tsk); int (*key_alloc)(struct key *key, struct task_struct *tsk, unsigned long flags);
void (*key_free)(struct key *key); void (*key_free)(struct key *key);
int (*key_permission)(key_ref_t key_ref, int (*key_permission)(key_ref_t key_ref,
struct task_struct *context, struct task_struct *context,
@ -3040,9 +3041,10 @@ static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
static inline int security_key_alloc(struct key *key, static inline int security_key_alloc(struct key *key,
struct task_struct *tsk) struct task_struct *tsk,
unsigned long flags)
{ {
return security_ops->key_alloc(key, tsk); return security_ops->key_alloc(key, tsk, flags);
} }
static inline void security_key_free(struct key *key) static inline void security_key_free(struct key *key)
@ -3060,7 +3062,8 @@ static inline int security_key_permission(key_ref_t key_ref,
#else #else
static inline int security_key_alloc(struct key *key, static inline int security_key_alloc(struct key *key,
struct task_struct *tsk) struct task_struct *tsk,
unsigned long flags)
{ {
return 0; return 0;
} }

View File

@ -870,7 +870,8 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz
} }
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx) static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx,
unsigned long flags)
{ {
return 0; return 0;
} }

View File

@ -99,7 +99,8 @@ extern int install_process_keyring(struct task_struct *tsk);
extern struct key *request_key_and_link(struct key_type *type, extern struct key *request_key_and_link(struct key_type *type,
const char *description, const char *description,
const char *callout_info, const char *callout_info,
struct key *dest_keyring); struct key *dest_keyring,
unsigned long flags);
/* /*
* request_key authorisation * request_key authorisation

View File

@ -248,7 +248,7 @@ static inline void key_alloc_serial(struct key *key)
*/ */
struct key *key_alloc(struct key_type *type, const char *desc, struct key *key_alloc(struct key_type *type, const char *desc,
uid_t uid, gid_t gid, struct task_struct *ctx, uid_t uid, gid_t gid, struct task_struct *ctx,
key_perm_t perm, int not_in_quota) key_perm_t perm, unsigned long flags)
{ {
struct key_user *user = NULL; struct key_user *user = NULL;
struct key *key; struct key *key;
@ -269,12 +269,14 @@ struct key *key_alloc(struct key_type *type, const char *desc,
/* check that the user's quota permits allocation of another key and /* check that the user's quota permits allocation of another key and
* its description */ * its description */
if (!not_in_quota) { if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock); spin_lock(&user->lock);
if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
) user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
goto no_quota; )
goto no_quota;
}
user->qnkeys++; user->qnkeys++;
user->qnbytes += quotalen; user->qnbytes += quotalen;
@ -308,7 +310,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->payload.data = NULL; key->payload.data = NULL;
key->security = NULL; key->security = NULL;
if (!not_in_quota) if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
key->flags |= 1 << KEY_FLAG_IN_QUOTA; key->flags |= 1 << KEY_FLAG_IN_QUOTA;
memset(&key->type_data, 0, sizeof(key->type_data)); memset(&key->type_data, 0, sizeof(key->type_data));
@ -318,7 +320,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
#endif #endif
/* let the security module know about the key */ /* let the security module know about the key */
ret = security_key_alloc(key, ctx); ret = security_key_alloc(key, ctx, flags);
if (ret < 0) if (ret < 0)
goto security_error; goto security_error;
@ -332,7 +334,7 @@ error:
security_error: security_error:
kfree(key->description); kfree(key->description);
kmem_cache_free(key_jar, key); kmem_cache_free(key_jar, key);
if (!not_in_quota) { if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock); spin_lock(&user->lock);
user->qnkeys--; user->qnkeys--;
user->qnbytes -= quotalen; user->qnbytes -= quotalen;
@ -345,7 +347,7 @@ security_error:
no_memory_3: no_memory_3:
kmem_cache_free(key_jar, key); kmem_cache_free(key_jar, key);
no_memory_2: no_memory_2:
if (!not_in_quota) { if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock); spin_lock(&user->lock);
user->qnkeys--; user->qnkeys--;
user->qnbytes -= quotalen; user->qnbytes -= quotalen;
@ -761,7 +763,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
const char *description, const char *description,
const void *payload, const void *payload,
size_t plen, size_t plen,
int not_in_quota) unsigned long flags)
{ {
struct key_type *ktype; struct key_type *ktype;
struct key *keyring, *key = NULL; struct key *keyring, *key = NULL;
@ -822,7 +824,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* allocate a new key */ /* allocate a new key */
key = key_alloc(ktype, description, current->fsuid, current->fsgid, key = key_alloc(ktype, description, current->fsuid, current->fsgid,
current, perm, not_in_quota); current, perm, flags);
if (IS_ERR(key)) { if (IS_ERR(key)) {
key_ref = ERR_PTR(PTR_ERR(key)); key_ref = ERR_PTR(PTR_ERR(key));
goto error_3; goto error_3;

View File

@ -102,7 +102,7 @@ asmlinkage long sys_add_key(const char __user *_type,
/* create or update the requested key and add it to the target /* create or update the requested key and add it to the target
* keyring */ * keyring */
key_ref = key_create_or_update(keyring_ref, type, description, key_ref = key_create_or_update(keyring_ref, type, description,
payload, plen, 0); payload, plen, KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key_ref)) { if (!IS_ERR(key_ref)) {
ret = key_ref_to_ptr(key_ref)->serial; ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref); key_ref_put(key_ref);
@ -184,7 +184,8 @@ asmlinkage long sys_request_key(const char __user *_type,
/* do the search */ /* do the search */
key = request_key_and_link(ktype, description, callout_info, key = request_key_and_link(ktype, description, callout_info,
key_ref_to_ptr(dest_ref)); key_ref_to_ptr(dest_ref),
KEY_ALLOC_IN_QUOTA);
if (IS_ERR(key)) { if (IS_ERR(key)) {
ret = PTR_ERR(key); ret = PTR_ERR(key);
goto error5; goto error5;

View File

@ -240,7 +240,7 @@ static long keyring_read(const struct key *keyring,
* allocate a keyring and link into the destination keyring * allocate a keyring and link into the destination keyring
*/ */
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
struct task_struct *ctx, int not_in_quota, struct task_struct *ctx, unsigned long flags,
struct key *dest) struct key *dest)
{ {
struct key *keyring; struct key *keyring;
@ -249,7 +249,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
keyring = key_alloc(&key_type_keyring, description, keyring = key_alloc(&key_type_keyring, description,
uid, gid, ctx, uid, gid, ctx,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
not_in_quota); flags);
if (!IS_ERR(keyring)) { if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);

View File

@ -77,7 +77,8 @@ int alloc_uid_keyring(struct user_struct *user,
/* concoct a default session keyring */ /* concoct a default session keyring */
sprintf(buf, "_uid_ses.%u", user->uid); sprintf(buf, "_uid_ses.%u", user->uid);
session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, NULL); session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(session_keyring)) { if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring); ret = PTR_ERR(session_keyring);
goto error; goto error;
@ -87,8 +88,8 @@ int alloc_uid_keyring(struct user_struct *user,
* keyring */ * keyring */
sprintf(buf, "_uid.%u", user->uid); sprintf(buf, "_uid.%u", user->uid);
uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
session_keyring); KEY_ALLOC_IN_QUOTA, session_keyring);
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
key_put(session_keyring); key_put(session_keyring);
ret = PTR_ERR(uid_keyring); ret = PTR_ERR(uid_keyring);
@ -144,7 +145,8 @@ int install_thread_keyring(struct task_struct *tsk)
sprintf(buf, "_tid.%u", tsk->pid); sprintf(buf, "_tid.%u", tsk->pid);
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error; goto error;
@ -178,7 +180,8 @@ int install_process_keyring(struct task_struct *tsk)
if (!tsk->signal->process_keyring) { if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid); sprintf(buf, "_pid.%u", tsk->tgid);
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error; goto error;
@ -209,6 +212,7 @@ error:
static int install_session_keyring(struct task_struct *tsk, static int install_session_keyring(struct task_struct *tsk,
struct key *keyring) struct key *keyring)
{ {
unsigned long flags;
struct key *old; struct key *old;
char buf[20]; char buf[20];
@ -218,7 +222,12 @@ static int install_session_keyring(struct task_struct *tsk,
if (!keyring) { if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid); sprintf(buf, "_ses.%u", tsk->tgid);
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); flags = KEY_ALLOC_QUOTA_OVERRUN;
if (tsk->signal->session_keyring)
flags = KEY_ALLOC_IN_QUOTA;
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
flags, NULL);
if (IS_ERR(keyring)) if (IS_ERR(keyring))
return PTR_ERR(keyring); return PTR_ERR(keyring);
} }
@ -728,7 +737,8 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, 0); keyring = find_keyring_by_name(name, 0);
if (PTR_ERR(keyring) == -ENOKEY) { if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */ /* not found - try and create a new one */
keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 0, NULL); keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error2; goto error2;

View File

@ -48,8 +48,8 @@ static int call_sbin_request_key(struct key *key,
/* allocate a new session keyring */ /* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial); sprintf(desc, "_req.%u", key->serial);
keyring = keyring_alloc(desc, current->fsuid, current->fsgid, keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
current, 1, NULL); KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error_alloc; goto error_alloc;
@ -126,7 +126,8 @@ error_alloc:
*/ */
static struct key *__request_key_construction(struct key_type *type, static struct key *__request_key_construction(struct key_type *type,
const char *description, const char *description,
const char *callout_info) const char *callout_info,
unsigned long flags)
{ {
request_key_actor_t actor; request_key_actor_t actor;
struct key_construction cons; struct key_construction cons;
@ -134,12 +135,12 @@ static struct key *__request_key_construction(struct key_type *type,
struct key *key, *authkey; struct key *key, *authkey;
int ret, negated; int ret, negated;
kenter("%s,%s,%s", type->name, description, callout_info); kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags);
/* create a key and add it to the queue */ /* create a key and add it to the queue */
key = key_alloc(type, description, key = key_alloc(type, description,
current->fsuid, current->fsgid, current->fsuid, current->fsgid, current, KEY_POS_ALL,
current, KEY_POS_ALL, 0); flags);
if (IS_ERR(key)) if (IS_ERR(key))
goto alloc_failed; goto alloc_failed;
@ -258,15 +259,16 @@ alloc_failed:
static struct key *request_key_construction(struct key_type *type, static struct key *request_key_construction(struct key_type *type,
const char *description, const char *description,
struct key_user *user, struct key_user *user,
const char *callout_info) const char *callout_info,
unsigned long flags)
{ {
struct key_construction *pcons; struct key_construction *pcons;
struct key *key, *ckey; struct key *key, *ckey;
DECLARE_WAITQUEUE(myself, current); DECLARE_WAITQUEUE(myself, current);
kenter("%s,%s,{%d},%s", kenter("%s,%s,{%d},%s,%lx",
type->name, description, user->uid, callout_info); type->name, description, user->uid, callout_info, flags);
/* see if there's such a key under construction already */ /* see if there's such a key under construction already */
down_write(&key_construction_sem); down_write(&key_construction_sem);
@ -282,7 +284,8 @@ static struct key *request_key_construction(struct key_type *type,
} }
/* see about getting userspace to construct the key */ /* see about getting userspace to construct the key */
key = __request_key_construction(type, description, callout_info); key = __request_key_construction(type, description, callout_info,
flags);
error: error:
kleave(" = %p", key); kleave(" = %p", key);
return key; return key;
@ -389,14 +392,15 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
struct key *request_key_and_link(struct key_type *type, struct key *request_key_and_link(struct key_type *type,
const char *description, const char *description,
const char *callout_info, const char *callout_info,
struct key *dest_keyring) struct key *dest_keyring,
unsigned long flags)
{ {
struct key_user *user; struct key_user *user;
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
kenter("%s,%s,%s,%p", kenter("%s,%s,%s,%p,%lx",
type->name, description, callout_info, dest_keyring); type->name, description, callout_info, dest_keyring, flags);
/* search all the process keyrings for a key */ /* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match, key_ref = search_process_keyrings(type, description, type->match,
@ -429,7 +433,8 @@ struct key *request_key_and_link(struct key_type *type,
/* ask userspace (returns NULL if it waited on a key /* ask userspace (returns NULL if it waited on a key
* being constructed) */ * being constructed) */
key = request_key_construction(type, description, key = request_key_construction(type, description,
user, callout_info); user, callout_info,
flags);
if (key) if (key)
break; break;
@ -485,7 +490,8 @@ struct key *request_key(struct key_type *type,
const char *description, const char *description,
const char *callout_info) const char *callout_info)
{ {
return request_key_and_link(type, description, callout_info, NULL); return request_key_and_link(type, description, callout_info, NULL,
KEY_ALLOC_IN_QUOTA);
} /* end request_key() */ } /* end request_key() */

View File

@ -187,7 +187,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
authkey = key_alloc(&key_type_request_key_auth, desc, authkey = key_alloc(&key_type_request_key_auth, desc,
current->fsuid, current->fsgid, current, current->fsuid, current->fsgid, current,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
KEY_USR_VIEW, 1); KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(authkey)) { if (IS_ERR(authkey)) {
ret = PTR_ERR(authkey); ret = PTR_ERR(authkey);
goto error_alloc; goto error_alloc;

View File

@ -4264,7 +4264,8 @@ static int selinux_setprocattr(struct task_struct *p,
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
static int selinux_key_alloc(struct key *k, struct task_struct *tsk) static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
unsigned long flags)
{ {
struct task_security_struct *tsec = tsk->security; struct task_security_struct *tsec = tsk->security;
struct key_security_struct *ksec; struct key_security_struct *ksec;
@ -4513,8 +4514,10 @@ static __init int selinux_init(void)
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
/* Add security information to initial keyrings */ /* Add security information to initial keyrings */
security_key_alloc(&root_user_keyring, current); security_key_alloc(&root_user_keyring, current,
security_key_alloc(&root_session_keyring, current); KEY_ALLOC_NOT_IN_QUOTA);
security_key_alloc(&root_session_keyring, current,
KEY_ALLOC_NOT_IN_QUOTA);
#endif #endif
return 0; return 0;