aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
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)