diff options
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) |