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>
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>
21 static ssize_t
binary_sysctl(const int *name
, int nlen
,
22 void __user
*oldval
, size_t oldlen
, void __user
*newval
, size_t newlen
)
27 static void deprecated_sysctl_warning(const int *name
, int nlen
)
32 * CTL_KERN/KERN_VERSION is used by older glibc and cannot
35 if (nlen
>= 2 && name
[0] == CTL_KERN
&& name
[1] == KERN_VERSION
)
38 if (printk_ratelimit()) {
40 "warning: process `%s' used the deprecated sysctl "
41 "system call with ", current
->comm
);
42 for (i
= 0; i
< nlen
; i
++)
43 printk(KERN_CONT
"%d.", name
[i
]);
44 printk(KERN_CONT
"\n");
49 #define WARN_ONCE_HASH_BITS 8
50 #define WARN_ONCE_HASH_SIZE (1<<WARN_ONCE_HASH_BITS)
52 static DECLARE_BITMAP(warn_once_bitmap
, WARN_ONCE_HASH_SIZE
);
54 #define FNV32_OFFSET 2166136261U
55 #define FNV32_PRIME 0x01000193
58 * Print each legacy sysctl (approximately) only once.
59 * To avoid making the tables non-const use a external
61 * Worst case hash collision: 6, but very rarely.
62 * NOTE! We don't use the SMP-safe bit tests. We simply
65 static void warn_on_bintable(const int *name
, int nlen
)
68 u32 hash
= FNV32_OFFSET
;
70 for (i
= 0; i
< nlen
; i
++)
71 hash
= (hash
^ name
[i
]) * FNV32_PRIME
;
72 hash
%= WARN_ONCE_HASH_SIZE
;
73 if (__test_and_set_bit(hash
, warn_once_bitmap
))
75 deprecated_sysctl_warning(name
, nlen
);
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
)
81 int name
[CTL_MAXNAME
];
84 /* Check args->nlen. */
85 if (nlen
< 0 || nlen
> CTL_MAXNAME
)
87 /* Read in the sysctl name for simplicity */
88 for (i
= 0; i
< nlen
; i
++)
89 if (get_user(name
[i
], args_name
+ i
))
92 warn_on_bintable(name
, nlen
);
94 return binary_sysctl(name
, nlen
, oldval
, oldlen
, newval
, newlen
);
97 SYSCALL_DEFINE1(sysctl
, struct __sysctl_args __user
*, args
)
99 struct __sysctl_args tmp
;
103 if (copy_from_user(&tmp
, args
, sizeof(tmp
)))
106 if (tmp
.oldval
&& !tmp
.oldlenp
)
109 if (tmp
.oldlenp
&& get_user(oldlen
, tmp
.oldlenp
))
112 result
= do_sysctl(tmp
.name
, tmp
.nlen
, tmp
.oldval
, oldlen
,
113 tmp
.newval
, tmp
.newlen
);
120 if (tmp
.oldlenp
&& put_user(oldlen
, tmp
.oldlenp
))
129 struct compat_sysctl_args
{
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];
139 COMPAT_SYSCALL_DEFINE1(sysctl
, struct compat_sysctl_args __user
*, args
)
141 struct compat_sysctl_args tmp
;
142 compat_size_t __user
*compat_oldlenp
;
146 if (copy_from_user(&tmp
, args
, sizeof(tmp
)))
149 if (tmp
.oldval
&& !tmp
.oldlenp
)
152 compat_oldlenp
= compat_ptr(tmp
.oldlenp
);
153 if (compat_oldlenp
&& get_user(oldlen
, compat_oldlenp
))
156 result
= do_sysctl(compat_ptr(tmp
.name
), tmp
.nlen
,
157 compat_ptr(tmp
.oldval
), oldlen
,
158 compat_ptr(tmp
.newval
), tmp
.newlen
);
165 if (compat_oldlenp
&& put_user(oldlen
, compat_oldlenp
))
171 #endif /* CONFIG_COMPAT */