123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- #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>
- #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(const int *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;
- n = *name;
- 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;
- }
- static ssize_t binary_sysctl(const int *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen)
- {
- struct ctl_table_header *head;
- ssize_t error = -ENOTDIR;
- 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;
- }
- #else /* CONFIG_SYSCTL_SYSCALL */
- static ssize_t binary_sysctl(const int *ctl_name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen)
- {
- return -ENOSYS;
- }
- #endif /* CONFIG_SYSCTL_SYSCALL */
- static void deprecated_sysctl_warning(const int *name, int nlen)
- {
- static int msg_count;
- int i;
- /* Ignore accesses to kernel.version */
- if ((nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION))
- return;
- 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 < nlen; i++)
- printk("%d.", name[i]);
- printk("\n");
- }
- return;
- }
- static 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;
- }
- #ifdef CONFIG_COMPAT
- #include <asm/compat.h>
- struct compat_sysctl_args {
- compat_uptr_t name;
- int nlen;
- compat_uptr_t oldval;
- compat_uptr_t oldlenp;
- compat_uptr_t newval;
- compat_size_t newlen;
- compat_ulong_t __unused[4];
- };
- asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args)
- {
- struct compat_sysctl_args tmp;
- compat_size_t __user *compat_oldlenp;
- size_t __user *oldlenp = NULL;
- size_t oldlen = 0;
- ssize_t result;
- if (copy_from_user(&tmp, args, sizeof(tmp)))
- return -EFAULT;
- compat_oldlenp = compat_ptr(tmp.oldlenp);
- if (compat_oldlenp) {
- oldlenp = compat_alloc_user_space(sizeof(*compat_oldlenp));
- if (get_user(oldlen, compat_oldlenp) ||
- put_user(oldlen, oldlenp))
- return -EFAULT;
- }
- lock_kernel();
- result = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
- compat_ptr(tmp.oldval), oldlenp,
- compat_ptr(tmp.newval), tmp.newlen);
- unlock_kernel();
- if (oldlenp && !result) {
- if (get_user(oldlen, oldlenp) ||
- put_user(oldlen, compat_oldlenp))
- return -EFAULT;
- }
- return result;
- }
- #endif /* CONFIG_COMPAT */
|