Commit afa588b2651a03da4bc601a17a244b1cd97264f2
1 parent
b419148e56
Exists in
master
and in
4 other branches
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>
Showing 3 changed files with 186 additions and 166 deletions Side-by-side Diff
kernel/Makefile
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | |
5 | 5 | obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ |
6 | 6 | cpu.o exit.o itimer.o time.o softirq.o resource.o \ |
7 | - sysctl.o capability.o ptrace.o timer.o user.o \ | |
7 | + sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ | |
8 | 8 | signal.o sys.o kmod.o workqueue.o pid.o \ |
9 | 9 | rcupdate.o extable.o params.o posix-timers.o \ |
10 | 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ |
kernel/sysctl.c
... | ... | @@ -27,7 +27,6 @@ |
27 | 27 | #include <linux/security.h> |
28 | 28 | #include <linux/ctype.h> |
29 | 29 | #include <linux/kmemcheck.h> |
30 | -#include <linux/smp_lock.h> | |
31 | 30 | #include <linux/fs.h> |
32 | 31 | #include <linux/init.h> |
33 | 32 | #include <linux/kernel.h> |
... | ... | @@ -60,7 +59,6 @@ |
60 | 59 | #include <asm/io.h> |
61 | 60 | #endif |
62 | 61 | |
63 | -static int deprecated_sysctl_warning(struct __sysctl_args *args); | |
64 | 62 | |
65 | 63 | #if defined(CONFIG_SYSCTL) |
66 | 64 | |
... | ... | @@ -1766,122 +1764,6 @@ |
1766 | 1764 | spin_unlock(&sysctl_lock); |
1767 | 1765 | } |
1768 | 1766 | |
1769 | -#ifdef CONFIG_SYSCTL_SYSCALL | |
1770 | -/* Perform the actual read/write of a sysctl table entry. */ | |
1771 | -static int do_sysctl_strategy(struct ctl_table_root *root, | |
1772 | - struct ctl_table *table, | |
1773 | - void __user *oldval, size_t __user *oldlenp, | |
1774 | - void __user *newval, size_t newlen) | |
1775 | -{ | |
1776 | - int op = 0, rc; | |
1777 | - | |
1778 | - if (oldval) | |
1779 | - op |= MAY_READ; | |
1780 | - if (newval) | |
1781 | - op |= MAY_WRITE; | |
1782 | - if (sysctl_perm(root, table, op)) | |
1783 | - return -EPERM; | |
1784 | - | |
1785 | - if (table->strategy) { | |
1786 | - rc = table->strategy(table, oldval, oldlenp, newval, newlen); | |
1787 | - if (rc < 0) | |
1788 | - return rc; | |
1789 | - if (rc > 0) | |
1790 | - return 0; | |
1791 | - } | |
1792 | - | |
1793 | - /* If there is no strategy routine, or if the strategy returns | |
1794 | - * zero, proceed with automatic r/w */ | |
1795 | - if (table->data && table->maxlen) { | |
1796 | - rc = sysctl_data(table, oldval, oldlenp, newval, newlen); | |
1797 | - if (rc < 0) | |
1798 | - return rc; | |
1799 | - } | |
1800 | - return 0; | |
1801 | -} | |
1802 | - | |
1803 | -static int parse_table(int __user *name, int nlen, | |
1804 | - void __user *oldval, size_t __user *oldlenp, | |
1805 | - void __user *newval, size_t newlen, | |
1806 | - struct ctl_table_root *root, | |
1807 | - struct ctl_table *table) | |
1808 | -{ | |
1809 | - int n; | |
1810 | -repeat: | |
1811 | - if (!nlen) | |
1812 | - return -ENOTDIR; | |
1813 | - if (get_user(n, name)) | |
1814 | - return -EFAULT; | |
1815 | - for ( ; table->ctl_name || table->procname; table++) { | |
1816 | - if (!table->ctl_name) | |
1817 | - continue; | |
1818 | - if (n == table->ctl_name) { | |
1819 | - int error; | |
1820 | - if (table->child) { | |
1821 | - if (sysctl_perm(root, table, MAY_EXEC)) | |
1822 | - return -EPERM; | |
1823 | - name++; | |
1824 | - nlen--; | |
1825 | - table = table->child; | |
1826 | - goto repeat; | |
1827 | - } | |
1828 | - error = do_sysctl_strategy(root, table, | |
1829 | - oldval, oldlenp, | |
1830 | - newval, newlen); | |
1831 | - return error; | |
1832 | - } | |
1833 | - } | |
1834 | - return -ENOTDIR; | |
1835 | -} | |
1836 | - | |
1837 | -int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | |
1838 | - void __user *newval, size_t newlen) | |
1839 | -{ | |
1840 | - struct ctl_table_header *head; | |
1841 | - int error = -ENOTDIR; | |
1842 | - | |
1843 | - if (nlen <= 0 || nlen >= CTL_MAXNAME) | |
1844 | - return -ENOTDIR; | |
1845 | - if (oldval) { | |
1846 | - int old_len; | |
1847 | - if (!oldlenp || get_user(old_len, oldlenp)) | |
1848 | - return -EFAULT; | |
1849 | - } | |
1850 | - | |
1851 | - for (head = sysctl_head_next(NULL); head; | |
1852 | - head = sysctl_head_next(head)) { | |
1853 | - error = parse_table(name, nlen, oldval, oldlenp, | |
1854 | - newval, newlen, | |
1855 | - head->root, head->ctl_table); | |
1856 | - if (error != -ENOTDIR) { | |
1857 | - sysctl_head_finish(head); | |
1858 | - break; | |
1859 | - } | |
1860 | - } | |
1861 | - return error; | |
1862 | -} | |
1863 | - | |
1864 | -SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) | |
1865 | -{ | |
1866 | - struct __sysctl_args tmp; | |
1867 | - int error; | |
1868 | - | |
1869 | - if (copy_from_user(&tmp, args, sizeof(tmp))) | |
1870 | - return -EFAULT; | |
1871 | - | |
1872 | - error = deprecated_sysctl_warning(&tmp); | |
1873 | - if (error) | |
1874 | - goto out; | |
1875 | - | |
1876 | - lock_kernel(); | |
1877 | - error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, | |
1878 | - tmp.newval, tmp.newlen); | |
1879 | - unlock_kernel(); | |
1880 | -out: | |
1881 | - return error; | |
1882 | -} | |
1883 | -#endif /* CONFIG_SYSCTL_SYSCALL */ | |
1884 | - | |
1885 | 1767 | /* |
1886 | 1768 | * sysctl_perm does NOT grant the superuser all rights automatically, because |
1887 | 1769 | * some sysctl variables are readonly even to root. |
... | ... | @@ -3148,23 +3030,6 @@ |
3148 | 3030 | #else /* CONFIG_SYSCTL_SYSCALL */ |
3149 | 3031 | |
3150 | 3032 | |
3151 | -SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) | |
3152 | -{ | |
3153 | - struct __sysctl_args tmp; | |
3154 | - int error; | |
3155 | - | |
3156 | - if (copy_from_user(&tmp, args, sizeof(tmp))) | |
3157 | - return -EFAULT; | |
3158 | - | |
3159 | - error = deprecated_sysctl_warning(&tmp); | |
3160 | - | |
3161 | - /* If no error reading the parameters then just -ENOSYS ... */ | |
3162 | - if (!error) | |
3163 | - error = -ENOSYS; | |
3164 | - | |
3165 | - return error; | |
3166 | -} | |
3167 | - | |
3168 | 3033 | int sysctl_data(struct ctl_table *table, |
3169 | 3034 | void __user *oldval, size_t __user *oldlenp, |
3170 | 3035 | void __user *newval, size_t newlen) |
... | ... | @@ -3202,36 +3067,6 @@ |
3202 | 3067 | |
3203 | 3068 | #endif /* CONFIG_SYSCTL_SYSCALL */ |
3204 | 3069 | |
3205 | -static int deprecated_sysctl_warning(struct __sysctl_args *args) | |
3206 | -{ | |
3207 | - static int msg_count; | |
3208 | - int name[CTL_MAXNAME]; | |
3209 | - int i; | |
3210 | - | |
3211 | - /* Check args->nlen. */ | |
3212 | - if (args->nlen < 0 || args->nlen > CTL_MAXNAME) | |
3213 | - return -ENOTDIR; | |
3214 | - | |
3215 | - /* Read in the sysctl name for better debug message logging */ | |
3216 | - for (i = 0; i < args->nlen; i++) | |
3217 | - if (get_user(name[i], args->name + i)) | |
3218 | - return -EFAULT; | |
3219 | - | |
3220 | - /* Ignore accesses to kernel.version */ | |
3221 | - if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION)) | |
3222 | - return 0; | |
3223 | - | |
3224 | - if (msg_count < 5) { | |
3225 | - msg_count++; | |
3226 | - printk(KERN_INFO | |
3227 | - "warning: process `%s' used the deprecated sysctl " | |
3228 | - "system call with ", current->comm); | |
3229 | - for (i = 0; i < args->nlen; i++) | |
3230 | - printk("%d.", name[i]); | |
3231 | - printk("\n"); | |
3232 | - } | |
3233 | - return 0; | |
3234 | -} | |
3235 | 3070 | |
3236 | 3071 | /* |
3237 | 3072 | * No sense putting this after each symbol definition, twice, |
kernel/sysctl_binary.c
1 | +#include <linux/stat.h> | |
2 | +#include <linux/sysctl.h> | |
3 | +#include "../fs/xfs/linux-2.6/xfs_sysctl.h" | |
4 | +#include <linux/sunrpc/debug.h> | |
5 | +#include <linux/string.h> | |
6 | +#include <net/ip_vs.h> | |
7 | +#include <linux/syscalls.h> | |
8 | +#include <linux/namei.h> | |
9 | +#include <linux/mount.h> | |
10 | +#include <linux/fs.h> | |
11 | +#include <linux/nsproxy.h> | |
12 | +#include <linux/pid_namespace.h> | |
13 | +#include <linux/file.h> | |
14 | +#include <linux/ctype.h> | |
15 | +#include <linux/smp_lock.h> | |
16 | + | |
17 | +static int deprecated_sysctl_warning(struct __sysctl_args *args); | |
18 | + | |
19 | +#ifdef CONFIG_SYSCTL_SYSCALL | |
20 | + | |
21 | +/* Perform the actual read/write of a sysctl table entry. */ | |
22 | +static int do_sysctl_strategy(struct ctl_table_root *root, | |
23 | + struct ctl_table *table, | |
24 | + void __user *oldval, size_t __user *oldlenp, | |
25 | + void __user *newval, size_t newlen) | |
26 | +{ | |
27 | + int op = 0, rc; | |
28 | + | |
29 | + if (oldval) | |
30 | + op |= MAY_READ; | |
31 | + if (newval) | |
32 | + op |= MAY_WRITE; | |
33 | + if (sysctl_perm(root, table, op)) | |
34 | + return -EPERM; | |
35 | + | |
36 | + if (table->strategy) { | |
37 | + rc = table->strategy(table, oldval, oldlenp, newval, newlen); | |
38 | + if (rc < 0) | |
39 | + return rc; | |
40 | + if (rc > 0) | |
41 | + return 0; | |
42 | + } | |
43 | + | |
44 | + /* If there is no strategy routine, or if the strategy returns | |
45 | + * zero, proceed with automatic r/w */ | |
46 | + if (table->data && table->maxlen) { | |
47 | + rc = sysctl_data(table, oldval, oldlenp, newval, newlen); | |
48 | + if (rc < 0) | |
49 | + return rc; | |
50 | + } | |
51 | + return 0; | |
52 | +} | |
53 | + | |
54 | +static int parse_table(int __user *name, int nlen, | |
55 | + void __user *oldval, size_t __user *oldlenp, | |
56 | + void __user *newval, size_t newlen, | |
57 | + struct ctl_table_root *root, | |
58 | + struct ctl_table *table) | |
59 | +{ | |
60 | + int n; | |
61 | +repeat: | |
62 | + if (!nlen) | |
63 | + return -ENOTDIR; | |
64 | + if (get_user(n, name)) | |
65 | + return -EFAULT; | |
66 | + for ( ; table->ctl_name || table->procname; table++) { | |
67 | + if (!table->ctl_name) | |
68 | + continue; | |
69 | + if (n == table->ctl_name) { | |
70 | + int error; | |
71 | + if (table->child) { | |
72 | + if (sysctl_perm(root, table, MAY_EXEC)) | |
73 | + return -EPERM; | |
74 | + name++; | |
75 | + nlen--; | |
76 | + table = table->child; | |
77 | + goto repeat; | |
78 | + } | |
79 | + error = do_sysctl_strategy(root, table, | |
80 | + oldval, oldlenp, | |
81 | + newval, newlen); | |
82 | + return error; | |
83 | + } | |
84 | + } | |
85 | + return -ENOTDIR; | |
86 | +} | |
87 | + | |
88 | +int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | |
89 | + void __user *newval, size_t newlen) | |
90 | +{ | |
91 | + struct ctl_table_header *head; | |
92 | + int error = -ENOTDIR; | |
93 | + | |
94 | + if (nlen <= 0 || nlen >= CTL_MAXNAME) | |
95 | + return -ENOTDIR; | |
96 | + if (oldval) { | |
97 | + int old_len; | |
98 | + if (!oldlenp || get_user(old_len, oldlenp)) | |
99 | + return -EFAULT; | |
100 | + } | |
101 | + | |
102 | + for (head = sysctl_head_next(NULL); head; | |
103 | + head = sysctl_head_next(head)) { | |
104 | + error = parse_table(name, nlen, oldval, oldlenp, | |
105 | + newval, newlen, | |
106 | + head->root, head->ctl_table); | |
107 | + if (error != -ENOTDIR) { | |
108 | + sysctl_head_finish(head); | |
109 | + break; | |
110 | + } | |
111 | + } | |
112 | + return error; | |
113 | +} | |
114 | + | |
115 | +SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) | |
116 | +{ | |
117 | + struct __sysctl_args tmp; | |
118 | + int error; | |
119 | + | |
120 | + if (copy_from_user(&tmp, args, sizeof(tmp))) | |
121 | + return -EFAULT; | |
122 | + | |
123 | + error = deprecated_sysctl_warning(&tmp); | |
124 | + if (error) | |
125 | + goto out; | |
126 | + | |
127 | + lock_kernel(); | |
128 | + error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, | |
129 | + tmp.newval, tmp.newlen); | |
130 | + unlock_kernel(); | |
131 | +out: | |
132 | + return error; | |
133 | +} | |
134 | + | |
135 | +#else /* CONFIG_SYSCTL_SYSCALL */ | |
136 | + | |
137 | +SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) | |
138 | +{ | |
139 | + struct __sysctl_args tmp; | |
140 | + int error; | |
141 | + | |
142 | + if (copy_from_user(&tmp, args, sizeof(tmp))) | |
143 | + return -EFAULT; | |
144 | + | |
145 | + error = deprecated_sysctl_warning(&tmp); | |
146 | + | |
147 | + /* If no error reading the parameters then just -ENOSYS ... */ | |
148 | + if (!error) | |
149 | + error = -ENOSYS; | |
150 | + | |
151 | + return error; | |
152 | +} | |
153 | + | |
154 | +#endif /* CONFIG_SYSCTL_SYSCALL */ | |
155 | + | |
156 | +static int deprecated_sysctl_warning(struct __sysctl_args *args) | |
157 | +{ | |
158 | + static int msg_count; | |
159 | + int name[CTL_MAXNAME]; | |
160 | + int i; | |
161 | + | |
162 | + /* Check args->nlen. */ | |
163 | + if (args->nlen < 0 || args->nlen > CTL_MAXNAME) | |
164 | + return -ENOTDIR; | |
165 | + | |
166 | + /* Read in the sysctl name for better debug message logging */ | |
167 | + for (i = 0; i < args->nlen; i++) | |
168 | + if (get_user(name[i], args->name + i)) | |
169 | + return -EFAULT; | |
170 | + | |
171 | + /* Ignore accesses to kernel.version */ | |
172 | + if ((args->nlen == 2) && (name[0] == CTL_KERN) && (name[1] == KERN_VERSION)) | |
173 | + return 0; | |
174 | + | |
175 | + if (msg_count < 5) { | |
176 | + msg_count++; | |
177 | + printk(KERN_INFO | |
178 | + "warning: process `%s' used the deprecated sysctl " | |
179 | + "system call with ", current->comm); | |
180 | + for (i = 0; i < args->nlen; i++) | |
181 | + printk("%d.", name[i]); | |
182 | + printk("\n"); | |
183 | + } | |
184 | + return 0; | |
185 | +} |