aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2008-04-29 04:02:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:23 -0400
commitd7321cd62470b70d2717dae5a963e7a8fabff4d5 (patch)
tree1e3468e44239a310b03c3f8dabf754e64b6ad281 /kernel/sysctl.c
parent2c4c7155f25192da3511a6c911db4d08102d36c4 (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.c25
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. */
1437static int do_sysctl_strategy(struct ctl_table *table, 1437static 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,
1471static int parse_table(int __user *name, int nlen, 1472static 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
1567int sysctl_perm(struct ctl_table *table, int op) 1570int 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
1576static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) 1587static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)