Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : #include <linux/stat.h>
3 : : #include <linux/sysctl.h>
4 : : #include "../fs/xfs/xfs_sysctl.h"
5 : : #include <linux/sunrpc/debug.h>
6 : : #include <linux/string.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/netdevice.h>
16 : : #include <linux/kernel.h>
17 : : #include <linux/uuid.h>
18 : : #include <linux/slab.h>
19 : : #include <linux/compat.h>
20 : :
21 : : static ssize_t binary_sysctl(const int *name, int nlen,
22 : : void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
23 : : {
24 : : return -ENOSYS;
25 : : }
26 : :
27 : 0 : static void deprecated_sysctl_warning(const int *name, int nlen)
28 : : {
29 : 0 : int i;
30 : :
31 : : /*
32 : : * CTL_KERN/KERN_VERSION is used by older glibc and cannot
33 : : * ever go away.
34 : : */
35 [ # # # # : 0 : if (nlen >= 2 && name[0] == CTL_KERN && name[1] == KERN_VERSION)
# # ]
36 : : return;
37 : :
38 [ # # ]: 0 : if (printk_ratelimit()) {
39 : 0 : printk(KERN_INFO
40 : : "warning: process `%s' used the deprecated sysctl "
41 : 0 : "system call with ", current->comm);
42 [ # # ]: 0 : for (i = 0; i < nlen; i++)
43 : 0 : printk(KERN_CONT "%d.", name[i]);
44 : 0 : printk(KERN_CONT "\n");
45 : : }
46 : : return;
47 : : }
48 : :
49 : : #define WARN_ONCE_HASH_BITS 8
50 : : #define WARN_ONCE_HASH_SIZE (1<<WARN_ONCE_HASH_BITS)
51 : :
52 : : static DECLARE_BITMAP(warn_once_bitmap, WARN_ONCE_HASH_SIZE);
53 : :
54 : : #define FNV32_OFFSET 2166136261U
55 : : #define FNV32_PRIME 0x01000193
56 : :
57 : : /*
58 : : * Print each legacy sysctl (approximately) only once.
59 : : * To avoid making the tables non-const use a external
60 : : * hash-table instead.
61 : : * Worst case hash collision: 6, but very rarely.
62 : : * NOTE! We don't use the SMP-safe bit tests. We simply
63 : : * don't care enough.
64 : : */
65 : 0 : static void warn_on_bintable(const int *name, int nlen)
66 : : {
67 : 0 : int i;
68 : 0 : u32 hash = FNV32_OFFSET;
69 : :
70 [ # # ]: 0 : for (i = 0; i < nlen; i++)
71 : 0 : hash = (hash ^ name[i]) * FNV32_PRIME;
72 : 0 : hash %= WARN_ONCE_HASH_SIZE;
73 [ # # ]: 0 : if (__test_and_set_bit(hash, warn_once_bitmap))
74 : : return;
75 : 0 : deprecated_sysctl_warning(name, nlen);
76 : : }
77 : :
78 : : static ssize_t do_sysctl(int __user *args_name, int nlen,
79 : : void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
80 : : {
81 : : int name[CTL_MAXNAME];
82 : : int i;
83 : :
84 : : /* Check args->nlen. */
85 : : if (nlen < 0 || nlen > CTL_MAXNAME)
86 : : return -ENOTDIR;
87 : : /* Read in the sysctl name for simplicity */
88 : : for (i = 0; i < nlen; i++)
89 : : if (get_user(name[i], args_name + i))
90 : : return -EFAULT;
91 : :
92 : : warn_on_bintable(name, nlen);
93 : :
94 : : return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
95 : : }
96 : :
97 : 0 : SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
98 : : {
99 : 0 : struct __sysctl_args tmp;
100 : 0 : size_t oldlen = 0;
101 : 0 : ssize_t result;
102 : :
103 [ # # ]: 0 : if (copy_from_user(&tmp, args, sizeof(tmp)))
104 : : return -EFAULT;
105 : :
106 [ # # # # ]: 0 : if (tmp.oldval && !tmp.oldlenp)
107 : : return -EFAULT;
108 : :
109 [ # # # # ]: 0 : if (tmp.oldlenp && get_user(oldlen, tmp.oldlenp))
110 : : return -EFAULT;
111 : :
112 : 0 : result = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, oldlen,
113 : : tmp.newval, tmp.newlen);
114 : :
115 [ # # ]: 0 : if (result >= 0) {
116 : 0 : oldlen = result;
117 : 0 : result = 0;
118 : : }
119 : :
120 [ # # # # ]: 0 : if (tmp.oldlenp && put_user(oldlen, tmp.oldlenp))
121 : 0 : return -EFAULT;
122 : :
123 : : return result;
124 : : }
125 : :
126 : :
127 : : #ifdef CONFIG_COMPAT
128 : :
129 : : struct compat_sysctl_args {
130 : : compat_uptr_t name;
131 : : int nlen;
132 : : compat_uptr_t oldval;
133 : : compat_uptr_t oldlenp;
134 : : compat_uptr_t newval;
135 : : compat_size_t newlen;
136 : : compat_ulong_t __unused[4];
137 : : };
138 : :
139 : 0 : COMPAT_SYSCALL_DEFINE1(sysctl, struct compat_sysctl_args __user *, args)
140 : : {
141 : 0 : struct compat_sysctl_args tmp;
142 : 0 : compat_size_t __user *compat_oldlenp;
143 : 0 : size_t oldlen = 0;
144 : 0 : ssize_t result;
145 : :
146 [ # # ]: 0 : if (copy_from_user(&tmp, args, sizeof(tmp)))
147 : : return -EFAULT;
148 : :
149 [ # # # # ]: 0 : if (tmp.oldval && !tmp.oldlenp)
150 : : return -EFAULT;
151 : :
152 [ # # ]: 0 : compat_oldlenp = compat_ptr(tmp.oldlenp);
153 [ # # # # ]: 0 : if (compat_oldlenp && get_user(oldlen, compat_oldlenp))
154 : : return -EFAULT;
155 : :
156 : 0 : result = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
157 : : compat_ptr(tmp.oldval), oldlen,
158 : : compat_ptr(tmp.newval), tmp.newlen);
159 : :
160 [ # # ]: 0 : if (result >= 0) {
161 : 0 : oldlen = result;
162 : 0 : result = 0;
163 : : }
164 : :
165 [ # # # # ]: 0 : if (compat_oldlenp && put_user(oldlen, compat_oldlenp))
166 : 0 : return -EFAULT;
167 : :
168 : : return result;
169 : : }
170 : :
171 : : #endif /* CONFIG_COMPAT */
|