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