sysctl: Separate the binary sysctl logic into it's own file.
In preparation for more invasive cleanups separate the core binary sysctl logic into it's own file. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
This commit is contained in:
Родитель
b419148e56
Коммит
afa588b265
|
@ -4,7 +4,7 @@
|
|||
|
||||
obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
|
||||
cpu.o exit.o itimer.o time.o softirq.o resource.o \
|
||||
sysctl.o capability.o ptrace.o timer.o user.o \
|
||||
sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
|
||||
signal.o sys.o kmod.o workqueue.o pid.o \
|
||||
rcupdate.o extable.o params.o posix-timers.o \
|
||||
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
|
||||
|
|
165
kernel/sysctl.c
165
kernel/sysctl.c
|
@ -27,7 +27,6 @@
|
|||
#include <linux/security.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kmemcheck.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -60,7 +59,6 @@
|
|||
#include <asm/io.h>
|
||||
#endif
|
||||
|
||||
static int deprecated_sysctl_warning(struct __sysctl_args *args);
|
||||
|
||||
#if defined(CONFIG_SYSCTL)
|
||||
|
||||
|
@ -1766,122 +1764,6 @@ void register_sysctl_root(struct ctl_table_root *root)
|
|||
spin_unlock(&sysctl_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSCTL_SYSCALL
|
||||
/* Perform the actual read/write of a sysctl table entry. */
|
||||
static int do_sysctl_strategy(struct ctl_table_root *root,
|
||||
struct ctl_table *table,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
{
|
||||
int op = 0, rc;
|
||||
|
||||
if (oldval)
|
||||
op |= MAY_READ;
|
||||
if (newval)
|
||||
op |= MAY_WRITE;
|
||||
if (sysctl_perm(root, table, op))
|
||||
return -EPERM;
|
||||
|
||||
if (table->strategy) {
|
||||
rc = table->strategy(table, oldval, oldlenp, newval, newlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If there is no strategy routine, or if the strategy returns
|
||||
* zero, proceed with automatic r/w */
|
||||
if (table->data && table->maxlen) {
|
||||
rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
repeat:
|
||||
if (!nlen)
|
||||
return -ENOTDIR;
|
||||
if (get_user(n, name))
|
||||
return -EFAULT;
|
||||
for ( ; table->ctl_name || table->procname; table++) {
|
||||
if (!table->ctl_name)
|
||||
continue;
|
||||
if (n == table->ctl_name) {
|
||||
int error;
|
||||
if (table->child) {
|
||||
if (sysctl_perm(root, table, MAY_EXEC))
|
||||
return -EPERM;
|
||||
name++;
|
||||
nlen--;
|
||||
table = table->child;
|
||||
goto repeat;
|
||||
}
|
||||
error = do_sysctl_strategy(root, table,
|
||||
oldval, oldlenp,
|
||||
newval, newlen);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -ENOTDIR;
|
||||
}
|
||||
|
||||
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
int error = -ENOTDIR;
|
||||
|
||||
if (nlen <= 0 || nlen >= CTL_MAXNAME)
|
||||
return -ENOTDIR;
|
||||
if (oldval) {
|
||||
int old_len;
|
||||
if (!oldlenp || get_user(old_len, oldlenp))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
for (head = sysctl_head_next(NULL); head;
|
||||
head = sysctl_head_next(head)) {
|
||||
error = parse_table(name, nlen, oldval, oldlenp,
|
||||
newval, newlen,
|
||||
head->root, head->ctl_table);
|
||||
if (error != -ENOTDIR) {
|
||||
sysctl_head_finish(head);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
|
||||
{
|
||||
struct __sysctl_args tmp;
|
||||
int error;
|
||||
|
||||
if (copy_from_user(&tmp, args, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
||||
error = deprecated_sysctl_warning(&tmp);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
lock_kernel();
|
||||
error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
|
||||
tmp.newval, tmp.newlen);
|
||||
unlock_kernel();
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
#endif /* CONFIG_SYSCTL_SYSCALL */
|
||||
|
||||
/*
|
||||
* sysctl_perm does NOT grant the superuser all rights automatically, because
|
||||
* some sysctl variables are readonly even to root.
|
||||
|
@ -3148,23 +3030,6 @@ int sysctl_ms_jiffies(struct ctl_table *table,
|
|||
#else /* CONFIG_SYSCTL_SYSCALL */
|
||||
|
||||
|
||||
SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
|
||||
{
|
||||
struct __sysctl_args tmp;
|
||||
int error;
|
||||
|
||||
if (copy_from_user(&tmp, args, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
||||
error = deprecated_sysctl_warning(&tmp);
|
||||
|
||||
/* If no error reading the parameters then just -ENOSYS ... */
|
||||
if (!error)
|
||||
error = -ENOSYS;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int sysctl_data(struct ctl_table *table,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
|
@ -3202,36 +3067,6 @@ int sysctl_ms_jiffies(struct ctl_table *table,
|
|||
|
||||
#endif /* CONFIG_SYSCTL_SYSCALL */
|
||||
|
||||
static int deprecated_sysctl_warning(struct __sysctl_args *args)
|
||||
{
|
||||
static int msg_count;
|
||||
int name[CTL_MAXNAME];
|
||||
int i;
|
||||
|
||||
/* Check args->nlen. */
|
||||
if (args->nlen < 0 || args->nlen > CTL_MAXNAME)
|
||||
return -ENOTDIR;
|
||||
|
||||
/* Read in the sysctl name for better debug message logging */
|
||||
for (i = 0; i < args->nlen; i++)
|
||||
if (get_user(name[i], args->name + i))
|
||||
return -EFAULT;
|
||||
|
||||
/* Ignore accesses to kernel.version */
|
||||
if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
|
||||
return 0;
|
||||
|
||||
if (msg_count < 5) {
|
||||
msg_count++;
|
||||
printk(KERN_INFO
|
||||
"warning: process `%s' used the deprecated sysctl "
|
||||
"system call with ", current->comm);
|
||||
for (i = 0; i < args->nlen; i++)
|
||||
printk("%d.", name[i]);
|
||||
printk("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* No sense putting this after each symbol definition, twice,
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
#include <linux/stat.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
|
||||
#include <linux/sunrpc/debug.h>
|
||||
#include <linux/string.h>
|
||||
#include <net/ip_vs.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/smp_lock.h>
|
||||
|
||||
static int deprecated_sysctl_warning(struct __sysctl_args *args);
|
||||
|
||||
#ifdef CONFIG_SYSCTL_SYSCALL
|
||||
|
||||
/* Perform the actual read/write of a sysctl table entry. */
|
||||
static int do_sysctl_strategy(struct ctl_table_root *root,
|
||||
struct ctl_table *table,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
{
|
||||
int op = 0, rc;
|
||||
|
||||
if (oldval)
|
||||
op |= MAY_READ;
|
||||
if (newval)
|
||||
op |= MAY_WRITE;
|
||||
if (sysctl_perm(root, table, op))
|
||||
return -EPERM;
|
||||
|
||||
if (table->strategy) {
|
||||
rc = table->strategy(table, oldval, oldlenp, newval, newlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If there is no strategy routine, or if the strategy returns
|
||||
* zero, proceed with automatic r/w */
|
||||
if (table->data && table->maxlen) {
|
||||
rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
repeat:
|
||||
if (!nlen)
|
||||
return -ENOTDIR;
|
||||
if (get_user(n, name))
|
||||
return -EFAULT;
|
||||
for ( ; table->ctl_name || table->procname; table++) {
|
||||
if (!table->ctl_name)
|
||||
continue;
|
||||
if (n == table->ctl_name) {
|
||||
int error;
|
||||
if (table->child) {
|
||||
if (sysctl_perm(root, table, MAY_EXEC))
|
||||
return -EPERM;
|
||||
name++;
|
||||
nlen--;
|
||||
table = table->child;
|
||||
goto repeat;
|
||||
}
|
||||
error = do_sysctl_strategy(root, table,
|
||||
oldval, oldlenp,
|
||||
newval, newlen);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -ENOTDIR;
|
||||
}
|
||||
|
||||
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
int error = -ENOTDIR;
|
||||
|
||||
if (nlen <= 0 || nlen >= CTL_MAXNAME)
|
||||
return -ENOTDIR;
|
||||
if (oldval) {
|
||||
int old_len;
|
||||
if (!oldlenp || get_user(old_len, oldlenp))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
for (head = sysctl_head_next(NULL); head;
|
||||
head = sysctl_head_next(head)) {
|
||||
error = parse_table(name, nlen, oldval, oldlenp,
|
||||
newval, newlen,
|
||||
head->root, head->ctl_table);
|
||||
if (error != -ENOTDIR) {
|
||||
sysctl_head_finish(head);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
|
||||
{
|
||||
struct __sysctl_args tmp;
|
||||
int error;
|
||||
|
||||
if (copy_from_user(&tmp, args, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
||||
error = deprecated_sysctl_warning(&tmp);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
lock_kernel();
|
||||
error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
|
||||
tmp.newval, tmp.newlen);
|
||||
unlock_kernel();
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
#else /* CONFIG_SYSCTL_SYSCALL */
|
||||
|
||||
SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
|
||||
{
|
||||
struct __sysctl_args tmp;
|
||||
int error;
|
||||
|
||||
if (copy_from_user(&tmp, args, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
||||
error = deprecated_sysctl_warning(&tmp);
|
||||
|
||||
/* If no error reading the parameters then just -ENOSYS ... */
|
||||
if (!error)
|
||||
error = -ENOSYS;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SYSCTL_SYSCALL */
|
||||
|
||||
static int deprecated_sysctl_warning(struct __sysctl_args *args)
|
||||
{
|
||||
static int msg_count;
|
||||
int name[CTL_MAXNAME];
|
||||
int i;
|
||||
|
||||
/* Check args->nlen. */
|
||||
if (args->nlen < 0 || args->nlen > CTL_MAXNAME)
|
||||
return -ENOTDIR;
|
||||
|
||||
/* Read in the sysctl name for better debug message logging */
|
||||
for (i = 0; i < args->nlen; i++)
|
||||
if (get_user(name[i], args->name + i))
|
||||
return -EFAULT;
|
||||
|
||||
/* Ignore accesses to kernel.version */
|
||||
if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
|
||||
return 0;
|
||||
|
||||
if (msg_count < 5) {
|
||||
msg_count++;
|
||||
printk(KERN_INFO
|
||||
"warning: process `%s' used the deprecated sysctl "
|
||||
"system call with ", current->comm);
|
||||
for (i = 0; i < args->nlen; i++)
|
||||
printk("%d.", name[i]);
|
||||
printk("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
Загрузка…
Ссылка в новой задаче