diff options
author | Pavel Emelyanov <xemul@openvz.org> | 2008-04-29 04:02:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:23 -0400 |
commit | d7321cd62470b70d2717dae5a963e7a8fabff4d5 (patch) | |
tree | 1e3468e44239a310b03c3f8dabf754e64b6ad281 /kernel/sysctl.c | |
parent | 2c4c7155f25192da3511a6c911db4d08102d36c4 (diff) |
sysctl: add the ->permissions callback on the ctl_table_root
When reading from/writing to some table, a root, which this table came from,
may affect this table's permissions, depending on who is working with the
table.
The core hunk is at the bottom of this patch. All the rest is just pushing
the ctl_table_root argument up to the sysctl_perm() function.
This will be mostly (only?) used in the net sysctls.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Acked-by: David S. Miller <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Denis V. Lunev <den@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 874e813e40c8..d7ffdc59816a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -1434,7 +1434,8 @@ void register_sysctl_root(struct ctl_table_root *root) | |||
1434 | 1434 | ||
1435 | #ifdef CONFIG_SYSCTL_SYSCALL | 1435 | #ifdef CONFIG_SYSCTL_SYSCALL |
1436 | /* Perform the actual read/write of a sysctl table entry. */ | 1436 | /* Perform the actual read/write of a sysctl table entry. */ |
1437 | static int do_sysctl_strategy(struct ctl_table *table, | 1437 | static int do_sysctl_strategy(struct ctl_table_root *root, |
1438 | struct ctl_table *table, | ||
1438 | int __user *name, int nlen, | 1439 | int __user *name, int nlen, |
1439 | void __user *oldval, size_t __user *oldlenp, | 1440 | void __user *oldval, size_t __user *oldlenp, |
1440 | void __user *newval, size_t newlen) | 1441 | void __user *newval, size_t newlen) |
@@ -1445,7 +1446,7 @@ static int do_sysctl_strategy(struct ctl_table *table, | |||
1445 | op |= 004; | 1446 | op |= 004; |
1446 | if (newval) | 1447 | if (newval) |
1447 | op |= 002; | 1448 | op |= 002; |
1448 | if (sysctl_perm(table, op)) | 1449 | if (sysctl_perm(root, table, op)) |
1449 | return -EPERM; | 1450 | return -EPERM; |
1450 | 1451 | ||
1451 | if (table->strategy) { | 1452 | if (table->strategy) { |
@@ -1471,6 +1472,7 @@ static int do_sysctl_strategy(struct ctl_table *table, | |||
1471 | static int parse_table(int __user *name, int nlen, | 1472 | static int parse_table(int __user *name, int nlen, |
1472 | void __user *oldval, size_t __user *oldlenp, | 1473 | void __user *oldval, size_t __user *oldlenp, |
1473 | void __user *newval, size_t newlen, | 1474 | void __user *newval, size_t newlen, |
1475 | struct ctl_table_root *root, | ||
1474 | struct ctl_table *table) | 1476 | struct ctl_table *table) |
1475 | { | 1477 | { |
1476 | int n; | 1478 | int n; |
@@ -1485,14 +1487,14 @@ repeat: | |||
1485 | if (n == table->ctl_name) { | 1487 | if (n == table->ctl_name) { |
1486 | int error; | 1488 | int error; |
1487 | if (table->child) { | 1489 | if (table->child) { |
1488 | if (sysctl_perm(table, 001)) | 1490 | if (sysctl_perm(root, table, 001)) |
1489 | return -EPERM; | 1491 | return -EPERM; |
1490 | name++; | 1492 | name++; |
1491 | nlen--; | 1493 | nlen--; |
1492 | table = table->child; | 1494 | table = table->child; |
1493 | goto repeat; | 1495 | goto repeat; |
1494 | } | 1496 | } |
1495 | error = do_sysctl_strategy(table, name, nlen, | 1497 | error = do_sysctl_strategy(root, table, name, nlen, |
1496 | oldval, oldlenp, | 1498 | oldval, oldlenp, |
1497 | newval, newlen); | 1499 | newval, newlen); |
1498 | return error; | 1500 | return error; |
@@ -1518,7 +1520,8 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol | |||
1518 | for (head = sysctl_head_next(NULL); head; | 1520 | for (head = sysctl_head_next(NULL); head; |
1519 | head = sysctl_head_next(head)) { | 1521 | head = sysctl_head_next(head)) { |
1520 | error = parse_table(name, nlen, oldval, oldlenp, | 1522 | error = parse_table(name, nlen, oldval, oldlenp, |
1521 | newval, newlen, head->ctl_table); | 1523 | newval, newlen, |
1524 | head->root, head->ctl_table); | ||
1522 | if (error != -ENOTDIR) { | 1525 | if (error != -ENOTDIR) { |
1523 | sysctl_head_finish(head); | 1526 | sysctl_head_finish(head); |
1524 | break; | 1527 | break; |
@@ -1564,13 +1567,21 @@ static int test_perm(int mode, int op) | |||
1564 | return -EACCES; | 1567 | return -EACCES; |
1565 | } | 1568 | } |
1566 | 1569 | ||
1567 | int sysctl_perm(struct ctl_table *table, int op) | 1570 | int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op) |
1568 | { | 1571 | { |
1569 | int error; | 1572 | int error; |
1573 | int mode; | ||
1574 | |||
1570 | error = security_sysctl(table, op); | 1575 | error = security_sysctl(table, op); |
1571 | if (error) | 1576 | if (error) |
1572 | return error; | 1577 | return error; |
1573 | return test_perm(table->mode, op); | 1578 | |
1579 | if (root->permissions) | ||
1580 | mode = root->permissions(root, current->nsproxy, table); | ||
1581 | else | ||
1582 | mode = table->mode; | ||
1583 | |||
1584 | return test_perm(mode, op); | ||
1574 | } | 1585 | } |
1575 | 1586 | ||
1576 | static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) | 1587 | static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) |