diff options
-rw-r--r-- | Documentation/keys.txt | 24 | ||||
-rw-r--r-- | include/linux/key.h | 5 | ||||
-rw-r--r-- | kernel/sysctl.c | 9 | ||||
-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 |
9 files changed, 131 insertions, 16 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index be424b02437d..d5c7a57d1700 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
@@ -170,7 +170,8 @@ The key service provides a number of features besides keys: | |||
170 | amount of description and payload space that can be consumed. | 170 | amount of description and payload space that can be consumed. |
171 | 171 | ||
172 | The user can view information on this and other statistics through procfs | 172 | The user can view information on this and other statistics through procfs |
173 | files. | 173 | files. The root user may also alter the quota limits through sysctl files |
174 | (see the section "New procfs files"). | ||
174 | 175 | ||
175 | Process-specific and thread-specific keyrings are not counted towards a | 176 | Process-specific and thread-specific keyrings are not counted towards a |
176 | user's quota. | 177 | user's quota. |
@@ -329,6 +330,27 @@ about the status of the key service: | |||
329 | <bytes>/<max> Key size quota | 330 | <bytes>/<max> Key size quota |
330 | 331 | ||
331 | 332 | ||
333 | Four new sysctl files have been added also for the purpose of controlling the | ||
334 | quota limits on keys: | ||
335 | |||
336 | (*) /proc/sys/kernel/keys/root_maxkeys | ||
337 | /proc/sys/kernel/keys/root_maxbytes | ||
338 | |||
339 | These files hold the maximum number of keys that root may have and the | ||
340 | maximum total number of bytes of data that root may have stored in those | ||
341 | keys. | ||
342 | |||
343 | (*) /proc/sys/kernel/keys/maxkeys | ||
344 | /proc/sys/kernel/keys/maxbytes | ||
345 | |||
346 | These files hold the maximum number of keys that each non-root user may | ||
347 | have and the maximum total number of bytes of data that each of those | ||
348 | users may have stored in their keys. | ||
349 | |||
350 | Root may alter these by writing each new limit as a decimal number string to | ||
351 | the appropriate file. | ||
352 | |||
353 | |||
332 | =============================== | 354 | =============================== |
333 | USERSPACE SYSTEM CALL INTERFACE | 355 | USERSPACE SYSTEM CALL INTERFACE |
334 | =============================== | 356 | =============================== |
diff --git a/include/linux/key.h b/include/linux/key.h index 2effd031a817..ad02d9cfe170 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/rbtree.h> | 20 | #include <linux/rbtree.h> |
21 | #include <linux/rcupdate.h> | 21 | #include <linux/rcupdate.h> |
22 | #include <linux/sysctl.h> | ||
22 | #include <asm/atomic.h> | 23 | #include <asm/atomic.h> |
23 | 24 | ||
24 | #ifdef __KERNEL__ | 25 | #ifdef __KERNEL__ |
@@ -265,6 +266,10 @@ extern struct key *key_lookup(key_serial_t id); | |||
265 | 266 | ||
266 | #define key_serial(key) ((key) ? (key)->serial : 0) | 267 | #define key_serial(key) ((key) ? (key)->serial : 0) |
267 | 268 | ||
269 | #ifdef CONFIG_SYSCTL | ||
270 | extern ctl_table key_sysctls[]; | ||
271 | #endif | ||
272 | |||
268 | /* | 273 | /* |
269 | * the userspace interface | 274 | * the userspace interface |
270 | */ | 275 | */ |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index fd3364827ccf..0a1d2733cf41 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/writeback.h> | 38 | #include <linux/writeback.h> |
39 | #include <linux/hugetlb.h> | 39 | #include <linux/hugetlb.h> |
40 | #include <linux/initrd.h> | 40 | #include <linux/initrd.h> |
41 | #include <linux/key.h> | ||
41 | #include <linux/times.h> | 42 | #include <linux/times.h> |
42 | #include <linux/limits.h> | 43 | #include <linux/limits.h> |
43 | #include <linux/dcache.h> | 44 | #include <linux/dcache.h> |
@@ -809,6 +810,14 @@ static struct ctl_table kern_table[] = { | |||
809 | .proc_handler = &proc_dostring, | 810 | .proc_handler = &proc_dostring, |
810 | .strategy = &sysctl_string, | 811 | .strategy = &sysctl_string, |
811 | }, | 812 | }, |
813 | #ifdef CONFIG_KEYS | ||
814 | { | ||
815 | .ctl_name = CTL_UNNUMBERED, | ||
816 | .procname = "keys", | ||
817 | .mode = 0555, | ||
818 | .child = key_sysctls, | ||
819 | }, | ||
820 | #endif | ||
812 | /* | 821 | /* |
813 | * NOTE: do not add new entries to this table unless you have read | 822 | * NOTE: do not add new entries to this table unless you have read |
814 | * Documentation/sysctl/ctl_unnumbered.txt | 823 | * Documentation/sysctl/ctl_unnumbered.txt |
diff --git a/security/keys/Makefile b/security/keys/Makefile index 5145adfb6a05..747a464943af 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
@@ -14,3 +14,4 @@ obj-y := \ | |||
14 | 14 | ||
15 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 15 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
16 | obj-$(CONFIG_PROC_FS) += proc.o | 16 | obj-$(CONFIG_PROC_FS) += proc.o |
17 | obj-$(CONFIG_SYSCTL) += sysctl.o | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 2ab38854c47f..8c05587f5018 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -57,10 +57,6 @@ struct key_user { | |||
57 | int qnbytes; /* number of bytes allocated to this user */ | 57 | int qnbytes; /* number of bytes allocated to this user */ |
58 | }; | 58 | }; |
59 | 59 | ||
60 | #define KEYQUOTA_MAX_KEYS 100 | ||
61 | #define KEYQUOTA_MAX_BYTES 10000 | ||
62 | #define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ | ||
63 | |||
64 | extern struct rb_root key_user_tree; | 60 | extern struct rb_root key_user_tree; |
65 | extern spinlock_t key_user_lock; | 61 | extern spinlock_t key_user_lock; |
66 | extern struct key_user root_key_user; | 62 | extern struct key_user root_key_user; |
@@ -68,6 +64,16 @@ extern struct key_user root_key_user; | |||
68 | extern struct key_user *key_user_lookup(uid_t uid); | 64 | extern struct key_user *key_user_lookup(uid_t uid); |
69 | extern void key_user_put(struct key_user *user); | 65 | extern void key_user_put(struct key_user *user); |
70 | 66 | ||
67 | /* | ||
68 | * key quota limits | ||
69 | * - root has its own separate limits to everyone else | ||
70 | */ | ||
71 | extern unsigned key_quota_root_maxkeys; | ||
72 | extern unsigned key_quota_root_maxbytes; | ||
73 | extern unsigned key_quota_maxkeys; | ||
74 | extern unsigned key_quota_maxbytes; | ||
75 | |||
76 | #define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ | ||
71 | 77 | ||
72 | 78 | ||
73 | extern struct rb_root key_serial_tree; | 79 | extern struct rb_root key_serial_tree; |
diff --git a/security/keys/key.c b/security/keys/key.c index 46f125aa7fa3..14948cf83ef6 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -27,6 +27,11 @@ DEFINE_SPINLOCK(key_serial_lock); | |||
27 | struct rb_root key_user_tree; /* tree of quota records indexed by UID */ | 27 | struct rb_root key_user_tree; /* tree of quota records indexed by UID */ |
28 | DEFINE_SPINLOCK(key_user_lock); | 28 | DEFINE_SPINLOCK(key_user_lock); |
29 | 29 | ||
30 | unsigned int key_quota_root_maxkeys = 200; /* root's key count quota */ | ||
31 | unsigned int key_quota_root_maxbytes = 20000; /* root's key space quota */ | ||
32 | unsigned int key_quota_maxkeys = 200; /* general key count quota */ | ||
33 | unsigned int key_quota_maxbytes = 20000; /* general key space quota */ | ||
34 | |||
30 | static LIST_HEAD(key_types_list); | 35 | static LIST_HEAD(key_types_list); |
31 | static DECLARE_RWSEM(key_types_sem); | 36 | static DECLARE_RWSEM(key_types_sem); |
32 | 37 | ||
@@ -236,11 +241,16 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
236 | /* check that the user's quota permits allocation of another key and | 241 | /* check that the user's quota permits allocation of another key and |
237 | * its description */ | 242 | * its description */ |
238 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { | 243 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { |
244 | unsigned maxkeys = (uid == 0) ? | ||
245 | key_quota_root_maxkeys : key_quota_maxkeys; | ||
246 | unsigned maxbytes = (uid == 0) ? | ||
247 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
248 | |||
239 | spin_lock(&user->lock); | 249 | spin_lock(&user->lock); |
240 | if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { | 250 | if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { |
241 | if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || | 251 | if (user->qnkeys + 1 >= maxkeys || |
242 | user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES | 252 | user->qnbytes + quotalen >= maxbytes || |
243 | ) | 253 | user->qnbytes + quotalen < user->qnbytes) |
244 | goto no_quota; | 254 | goto no_quota; |
245 | } | 255 | } |
246 | 256 | ||
@@ -345,11 +355,14 @@ int key_payload_reserve(struct key *key, size_t datalen) | |||
345 | 355 | ||
346 | /* contemplate the quota adjustment */ | 356 | /* contemplate the quota adjustment */ |
347 | if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 357 | if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
358 | unsigned maxbytes = (key->user->uid == 0) ? | ||
359 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
360 | |||
348 | spin_lock(&key->user->lock); | 361 | spin_lock(&key->user->lock); |
349 | 362 | ||
350 | if (delta > 0 && | 363 | if (delta > 0 && |
351 | key->user->qnbytes + delta > KEYQUOTA_MAX_BYTES | 364 | (key->user->qnbytes + delta >= maxbytes || |
352 | ) { | 365 | key->user->qnbytes + delta < key->user->qnbytes)) { |
353 | ret = -EDQUOT; | 366 | ret = -EDQUOT; |
354 | } | 367 | } |
355 | else { | 368 | else { |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 993be634a5ef..acc9c89e40a8 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) | |||
731 | 731 | ||
732 | /* transfer the quota burden to the new user */ | 732 | /* transfer the quota burden to the new user */ |
733 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 733 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
734 | unsigned maxkeys = (uid == 0) ? | ||
735 | key_quota_root_maxkeys : key_quota_maxkeys; | ||
736 | unsigned maxbytes = (uid == 0) ? | ||
737 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
738 | |||
734 | spin_lock(&newowner->lock); | 739 | spin_lock(&newowner->lock); |
735 | if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || | 740 | if (newowner->qnkeys + 1 >= maxkeys || |
736 | newowner->qnbytes + key->quotalen >= | 741 | newowner->qnbytes + key->quotalen >= maxbytes || |
737 | KEYQUOTA_MAX_BYTES) | 742 | newowner->qnbytes + key->quotalen < |
743 | newowner->qnbytes) | ||
738 | goto quota_overrun; | 744 | goto quota_overrun; |
739 | 745 | ||
740 | newowner->qnkeys++; | 746 | newowner->qnkeys++; |
diff --git a/security/keys/proc.c b/security/keys/proc.c index e54679b848cf..f619170da760 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) | |||
242 | { | 242 | { |
243 | struct rb_node *_p = v; | 243 | struct rb_node *_p = v; |
244 | struct key_user *user = rb_entry(_p, struct key_user, node); | 244 | struct key_user *user = rb_entry(_p, struct key_user, node); |
245 | unsigned maxkeys = (user->uid == 0) ? | ||
246 | key_quota_root_maxkeys : key_quota_maxkeys; | ||
247 | unsigned maxbytes = (user->uid == 0) ? | ||
248 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
245 | 249 | ||
246 | seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", | 250 | seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", |
247 | user->uid, | 251 | user->uid, |
@@ -249,10 +253,9 @@ static int proc_key_users_show(struct seq_file *m, void *v) | |||
249 | atomic_read(&user->nkeys), | 253 | atomic_read(&user->nkeys), |
250 | atomic_read(&user->nikeys), | 254 | atomic_read(&user->nikeys), |
251 | user->qnkeys, | 255 | user->qnkeys, |
252 | KEYQUOTA_MAX_KEYS, | 256 | maxkeys, |
253 | user->qnbytes, | 257 | user->qnbytes, |
254 | KEYQUOTA_MAX_BYTES | 258 | maxbytes); |
255 | ); | ||
256 | 259 | ||
257 | return 0; | 260 | return 0; |
258 | 261 | ||
diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c new file mode 100644 index 000000000000..b611d493c2d8 --- /dev/null +++ b/security/keys/sysctl.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* Key management controls | ||
2 | * | ||
3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/key.h> | ||
13 | #include <linux/sysctl.h> | ||
14 | #include "internal.h" | ||
15 | |||
16 | ctl_table key_sysctls[] = { | ||
17 | { | ||
18 | .ctl_name = CTL_UNNUMBERED, | ||
19 | .procname = "maxkeys", | ||
20 | .data = &key_quota_maxkeys, | ||
21 | .maxlen = sizeof(unsigned), | ||
22 | .mode = 0644, | ||
23 | .proc_handler = &proc_dointvec, | ||
24 | }, | ||
25 | { | ||
26 | .ctl_name = CTL_UNNUMBERED, | ||
27 | .procname = "maxbytes", | ||
28 | .data = &key_quota_maxbytes, | ||
29 | .maxlen = sizeof(unsigned), | ||
30 | .mode = 0644, | ||
31 | .proc_handler = &proc_dointvec, | ||
32 | }, | ||
33 | { | ||
34 | .ctl_name = CTL_UNNUMBERED, | ||
35 | .procname = "root_maxkeys", | ||
36 | .data = &key_quota_root_maxkeys, | ||
37 | .maxlen = sizeof(unsigned), | ||
38 | .mode = 0644, | ||
39 | .proc_handler = &proc_dointvec, | ||
40 | }, | ||
41 | { | ||
42 | .ctl_name = CTL_UNNUMBERED, | ||
43 | .procname = "root_maxbytes", | ||
44 | .data = &key_quota_root_maxbytes, | ||
45 | .maxlen = sizeof(unsigned), | ||
46 | .mode = 0644, | ||
47 | .proc_handler = &proc_dointvec, | ||
48 | }, | ||
49 | { .ctl_name = 0 } | ||
50 | }; | ||