Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e047ef5 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

[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: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f116629d
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -248,7 +248,14 @@ extern struct key *key_alloc(struct key_type *type,
			     const char *desc,
			     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);


#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_instantiate_and_link(struct key *key,
				    const void *data,
@@ -285,7 +292,7 @@ extern key_ref_t key_create_or_update(key_ref_t keyring,
				      const char *description,
				      const void *payload,
				      size_t plen,
				      int not_in_quota);
				      unsigned long flags);

extern int key_update(key_ref_t key,
		      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,
				 struct task_struct *ctx,
				 int not_in_quota,
				 unsigned long flags,
				 struct key *dest);

extern int keyring_clear(struct key *keyring);
+7 −4
Original line number Diff line number Diff line
@@ -862,6 +862,7 @@ struct swap_info_struct;
 *	Permit allocation of a key and assign security data. Note that key does
 *	not have a serial number assigned at this point.
 *	@key points to the key.
 *	@flags is the allocation flags
 *	Return 0 if permission is granted, -ve error otherwise.
 * @key_free:
 *	Notification of destruction; free security data.
@@ -1324,7 +1325,7 @@ struct security_operations {

	/* key management security hooks */
#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);
	int (*key_permission)(key_ref_t key_ref,
			      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_SECURITY
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)
@@ -3060,7 +3062,8 @@ static inline int security_key_permission(key_ref_t key_ref,
#else

static inline int security_key_alloc(struct key *key,
				     struct task_struct *tsk)
				     struct task_struct *tsk,
				     unsigned long flags)
{
	return 0;
}
+2 −1
Original line number Diff line number Diff line
@@ -870,7 +870,8 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz
}

#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;
}
+2 −1
Original line number Diff line number Diff line
@@ -99,7 +99,8 @@ extern int install_process_keyring(struct task_struct *tsk);
extern struct key *request_key_and_link(struct key_type *type,
					const char *description,
					const char *callout_info,
					struct key *dest_keyring);
					struct key *dest_keyring,
					unsigned long flags);

/*
 * request_key authorisation
+14 −12
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ static inline void key_alloc_serial(struct key *key)
 */
struct key *key_alloc(struct key_type *type, const char *desc,
		      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 *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
	 * its description */
	if (!not_in_quota) {
	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
		spin_lock(&user->lock);
		if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
			if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
			    user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
			    )
				goto no_quota;
		}

		user->qnkeys++;
		user->qnbytes += quotalen;
@@ -308,7 +310,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
	key->payload.data = NULL;
	key->security = NULL;

	if (!not_in_quota)
	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
		key->flags |= 1 << KEY_FLAG_IN_QUOTA;

	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

	/* let the security module know about the key */
	ret = security_key_alloc(key, ctx);
	ret = security_key_alloc(key, ctx, flags);
	if (ret < 0)
		goto security_error;

@@ -332,7 +334,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
security_error:
	kfree(key->description);
	kmem_cache_free(key_jar, key);
	if (!not_in_quota) {
	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
		spin_lock(&user->lock);
		user->qnkeys--;
		user->qnbytes -= quotalen;
@@ -345,7 +347,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
no_memory_3:
	kmem_cache_free(key_jar, key);
no_memory_2:
	if (!not_in_quota) {
	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
		spin_lock(&user->lock);
		user->qnkeys--;
		user->qnbytes -= quotalen;
@@ -761,7 +763,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
			       const char *description,
			       const void *payload,
			       size_t plen,
			       int not_in_quota)
			       unsigned long flags)
{
	struct key_type *ktype;
	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 */
	key = key_alloc(ktype, description, current->fsuid, current->fsgid,
			current, perm, not_in_quota);
			current, perm, flags);
	if (IS_ERR(key)) {
		key_ref = ERR_PTR(PTR_ERR(key));
		goto error_3;
Loading