Commit 2830b683 authored by Eric W. Biederman's avatar Eric W. Biederman

sysctl: Refactor the binary sysctl handling to remove duplicate code

Read in the binary sysctl path once, instead of reread it
from user space each time the code needs to access a path
element.

The deprecated sysctl warning is moved to do_sysctl so
that the compat_sysctl entries syscalls will also warn.

The return of -ENOSYS when !CONFIG_SYSCTL_SYSCALL is moved
to binary_sysctl.  Always leaving a do_sysctl available
that handles !CONFIG_SYSCTL_SYSCALL and printing the
deprecated sysctl warning allows for a single defitition
of the sysctl syscall.
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
parent afa588b2
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
static int deprecated_sysctl_warning(struct __sysctl_args *args);
#ifdef CONFIG_SYSCTL_SYSCALL #ifdef CONFIG_SYSCTL_SYSCALL
/* Perform the actual read/write of a sysctl table entry. */ /* Perform the actual read/write of a sysctl table entry. */
...@@ -51,7 +49,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root, ...@@ -51,7 +49,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
return 0; return 0;
} }
static int parse_table(int __user *name, int nlen, static int parse_table(const int *name, int nlen,
void __user *oldval, size_t __user *oldlenp, void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen, void __user *newval, size_t newlen,
struct ctl_table_root *root, struct ctl_table_root *root,
...@@ -61,8 +59,7 @@ static int parse_table(int __user *name, int nlen, ...@@ -61,8 +59,7 @@ static int parse_table(int __user *name, int nlen,
repeat: repeat:
if (!nlen) if (!nlen)
return -ENOTDIR; return -ENOTDIR;
if (get_user(n, name)) n = *name;
return -EFAULT;
for ( ; table->ctl_name || table->procname; table++) { for ( ; table->ctl_name || table->procname; table++) {
if (!table->ctl_name) if (!table->ctl_name)
continue; continue;
...@@ -85,19 +82,13 @@ repeat: ...@@ -85,19 +82,13 @@ repeat:
return -ENOTDIR; return -ENOTDIR;
} }
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, static ssize_t binary_sysctl(const int *name, int nlen,
void __user *newval, size_t newlen) void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{ {
struct ctl_table_header *head; struct ctl_table_header *head;
int error = -ENOTDIR; ssize_t 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; for (head = sysctl_head_next(NULL); head;
head = sysctl_head_next(head)) { head = sysctl_head_next(head)) {
...@@ -112,74 +103,76 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol ...@@ -112,74 +103,76 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
return error; 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 */ #else /* CONFIG_SYSCTL_SYSCALL */
SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) static ssize_t binary_sysctl(const int *ctl_name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{ {
struct __sysctl_args tmp; return -ENOSYS;
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 */ #endif /* CONFIG_SYSCTL_SYSCALL */
static int deprecated_sysctl_warning(struct __sysctl_args *args) static void deprecated_sysctl_warning(const int *name, int nlen)
{ {
static int msg_count; static int msg_count;
int name[CTL_MAXNAME];
int i; 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 */ /* Ignore accesses to kernel.version */
if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION)) if ((nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
return 0; return;
if (msg_count < 5) { if (msg_count < 5) {
msg_count++; msg_count++;
printk(KERN_INFO printk(KERN_INFO
"warning: process `%s' used the deprecated sysctl " "warning: process `%s' used the deprecated sysctl "
"system call with ", current->comm); "system call with ", current->comm);
for (i = 0; i < args->nlen; i++) for (i = 0; i < nlen; i++)
printk("%d.", name[i]); printk("%d.", name[i]);
printk("\n"); printk("\n");
} }
return 0; return;
}
int do_sysctl(int __user *args_name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
int name[CTL_MAXNAME];
size_t oldlen = 0;
int i;
if (nlen <= 0 || nlen >= CTL_MAXNAME)
return -ENOTDIR;
if (oldval && !oldlenp)
return -EFAULT;
if (oldlenp && get_user(oldlen, oldlenp))
return -EFAULT;
/* Read in the sysctl name for simplicity */
for (i = 0; i < nlen; i++)
if (get_user(name[i], args_name + i))
return -EFAULT;
deprecated_sysctl_warning(name, nlen);
return binary_sysctl(name, nlen, oldval, oldlenp, newval, newlen);
}
SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
{
struct __sysctl_args tmp;
int error;
if (copy_from_user(&tmp, args, sizeof(tmp)))
return -EFAULT;
lock_kernel();
error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
tmp.newval, tmp.newlen);
unlock_kernel();
return error;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment