diff options
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/Makefile | 1 | ||||
-rw-r--r-- | security/keys/internal.h | 14 | ||||
-rw-r--r-- | security/keys/key.c | 23 | ||||
-rw-r--r-- | security/keys/keyctl.c | 12 | ||||
-rw-r--r-- | security/keys/proc.c | 9 | ||||
-rw-r--r-- | security/keys/sysctl.c | 50 |
6 files changed, 94 insertions, 15 deletions
diff --git a/security/keys/Makefile b/security/keys/Makefile index 5145adfb6a0..747a464943a 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile @@ -14,3 +14,4 @@ obj-y := \ obj-$(CONFIG_KEYS_COMPAT) += compat.o obj-$(CONFIG_PROC_FS) += proc.o +obj-$(CONFIG_SYSCTL) += sysctl.o diff --git a/security/keys/internal.h b/security/keys/internal.h index 2ab38854c47..8c05587f501 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -57,10 +57,6 @@ struct key_user { int qnbytes; /* number of bytes allocated to this user */ }; -#define KEYQUOTA_MAX_KEYS 100 -#define KEYQUOTA_MAX_BYTES 10000 -#define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ - extern struct rb_root key_user_tree; extern spinlock_t key_user_lock; extern struct key_user root_key_user; @@ -68,6 +64,16 @@ extern struct key_user root_key_user; extern struct key_user *key_user_lookup(uid_t uid); extern void key_user_put(struct key_user *user); +/* + * key quota limits + * - root has its own separate limits to everyone else + */ +extern unsigned key_quota_root_maxkeys; +extern unsigned key_quota_root_maxbytes; +extern unsigned key_quota_maxkeys; +extern unsigned key_quota_maxbytes; + +#define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ extern struct rb_root key_serial_tree; diff --git a/security/keys/key.c b/security/keys/key.c index 46f125aa7fa..14948cf83ef 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -27,6 +27,11 @@ DEFINE_SPINLOCK(key_serial_lock); struct rb_root key_user_tree; /* tree of quota records indexed by UID */ DEFINE_SPINLOCK(key_user_lock); +unsigned int key_quota_root_maxkeys = 200; /* root's key count quota */ +unsigned int key_quota_root_maxbytes = 20000; /* root's key space quota */ +unsigned int key_quota_maxkeys = 200; /* general key count quota */ +unsigned int key_quota_maxbytes = 20000; /* general key space quota */ + static LIST_HEAD(key_types_list); static DECLARE_RWSEM(key_types_sem); @@ -236,11 +241,16 @@ 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 (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { + unsigned maxkeys = (uid == 0) ? + key_quota_root_maxkeys : key_quota_maxkeys; + unsigned maxbytes = (uid == 0) ? + key_quota_root_maxbytes : key_quota_maxbytes; + spin_lock(&user->lock); if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { - if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || - user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES - ) + if (user->qnkeys + 1 >= maxkeys || + user->qnbytes + quotalen >= maxbytes || + user->qnbytes + quotalen < user->qnbytes) goto no_quota; } @@ -345,11 +355,14 @@ int key_payload_reserve(struct key *key, size_t datalen) /* contemplate the quota adjustment */ if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { + unsigned maxbytes = (key->user->uid == 0) ? + key_quota_root_maxbytes : key_quota_maxbytes; + spin_lock(&key->user->lock); if (delta > 0 && - key->user->qnbytes + delta > KEYQUOTA_MAX_BYTES - ) { + (key->user->qnbytes + delta >= maxbytes || + key->user->qnbytes + delta < key->user->qnbytes)) { ret = -EDQUOT; } else { diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 993be634a5e..acc9c89e40a 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -731,10 +731,16 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) /* transfer the quota burden to the new user */ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { + unsigned maxkeys = (uid == 0) ? + key_quota_root_maxkeys : key_quota_maxkeys; + unsigned maxbytes = (uid == 0) ? + key_quota_root_maxbytes : key_quota_maxbytes; + spin_lock(&newowner->lock); - if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || - newowner->qnbytes + key->quotalen >= - KEYQUOTA_MAX_BYTES) + if (newowner->qnkeys + 1 >= maxkeys || + newowner->qnbytes + key->quotalen >= maxbytes || + newowner->qnbytes + key->quotalen < + newowner->qnbytes) goto quota_overrun; newowner->qnkeys++; diff --git a/security/keys/proc.c b/security/keys/proc.c index e54679b848c..f619170da76 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -242,6 +242,10 @@ static int proc_key_users_show(struct seq_file *m, void *v) { struct rb_node *_p = v; struct key_user *user = rb_entry(_p, struct key_user, node); + unsigned maxkeys = (user->uid == 0) ? + key_quota_root_maxkeys : key_quota_maxkeys; + unsigned maxbytes = (user->uid == 0) ? + key_quota_root_maxbytes : key_quota_maxbytes; seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", user->uid, @@ -249,10 +253,9 @@ static int proc_key_users_show(struct seq_file *m, void *v) atomic_read(&user->nkeys), atomic_read(&user->nikeys), user->qnkeys, - KEYQUOTA_MAX_KEYS, + maxkeys, user->qnbytes, - KEYQUOTA_MAX_BYTES - ); + maxbytes); return 0; diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c new file mode 100644 index 00000000000..b611d493c2d --- /dev/null +++ b/security/keys/sysctl.c @@ -0,0 +1,50 @@ +/* Key management controls + * + * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include <linux/key.h> +#include <linux/sysctl.h> +#include "internal.h" + +ctl_table key_sysctls[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "maxkeys", + .data = &key_quota_maxkeys, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "maxbytes", + .data = &key_quota_maxbytes, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "root_maxkeys", + .data = &key_quota_root_maxkeys, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "root_maxbytes", + .data = &key_quota_root_maxbytes, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 } +}; |