|
@@ -1434,7 +1434,8 @@ void register_sysctl_root(struct ctl_table_root *root)
|
|
|
|
|
|
#ifdef CONFIG_SYSCTL_SYSCALL
|
|
|
/* Perform the actual read/write of a sysctl table entry. */
|
|
|
-static int do_sysctl_strategy(struct ctl_table *table,
|
|
|
+static int do_sysctl_strategy(struct ctl_table_root *root,
|
|
|
+ struct ctl_table *table,
|
|
|
int __user *name, int nlen,
|
|
|
void __user *oldval, size_t __user *oldlenp,
|
|
|
void __user *newval, size_t newlen)
|
|
@@ -1445,7 +1446,7 @@ static int do_sysctl_strategy(struct ctl_table *table,
|
|
|
op |= 004;
|
|
|
if (newval)
|
|
|
op |= 002;
|
|
|
- if (sysctl_perm(table, op))
|
|
|
+ if (sysctl_perm(root, table, op))
|
|
|
return -EPERM;
|
|
|
|
|
|
if (table->strategy) {
|
|
@@ -1471,6 +1472,7 @@ static int do_sysctl_strategy(struct ctl_table *table,
|
|
|
static int parse_table(int __user *name, int nlen,
|
|
|
void __user *oldval, size_t __user *oldlenp,
|
|
|
void __user *newval, size_t newlen,
|
|
|
+ struct ctl_table_root *root,
|
|
|
struct ctl_table *table)
|
|
|
{
|
|
|
int n;
|
|
@@ -1485,14 +1487,14 @@ repeat:
|
|
|
if (n == table->ctl_name) {
|
|
|
int error;
|
|
|
if (table->child) {
|
|
|
- if (sysctl_perm(table, 001))
|
|
|
+ if (sysctl_perm(root, table, 001))
|
|
|
return -EPERM;
|
|
|
name++;
|
|
|
nlen--;
|
|
|
table = table->child;
|
|
|
goto repeat;
|
|
|
}
|
|
|
- error = do_sysctl_strategy(table, name, nlen,
|
|
|
+ error = do_sysctl_strategy(root, table, name, nlen,
|
|
|
oldval, oldlenp,
|
|
|
newval, newlen);
|
|
|
return error;
|
|
@@ -1518,7 +1520,8 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
|
|
|
for (head = sysctl_head_next(NULL); head;
|
|
|
head = sysctl_head_next(head)) {
|
|
|
error = parse_table(name, nlen, oldval, oldlenp,
|
|
|
- newval, newlen, head->ctl_table);
|
|
|
+ newval, newlen,
|
|
|
+ head->root, head->ctl_table);
|
|
|
if (error != -ENOTDIR) {
|
|
|
sysctl_head_finish(head);
|
|
|
break;
|
|
@@ -1564,13 +1567,21 @@ static int test_perm(int mode, int op)
|
|
|
return -EACCES;
|
|
|
}
|
|
|
|
|
|
-int sysctl_perm(struct ctl_table *table, int op)
|
|
|
+int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
|
|
|
{
|
|
|
int error;
|
|
|
+ int mode;
|
|
|
+
|
|
|
error = security_sysctl(table, op);
|
|
|
if (error)
|
|
|
return error;
|
|
|
- return test_perm(table->mode, op);
|
|
|
+
|
|
|
+ if (root->permissions)
|
|
|
+ mode = root->permissions(root, current->nsproxy, table);
|
|
|
+ else
|
|
|
+ mode = table->mode;
|
|
|
+
|
|
|
+ return test_perm(mode, op);
|
|
|
}
|
|
|
|
|
|
static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)
|