Blame view

kernel/sysctl_binary.c 3.82 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
afa588b26   Eric W. Biederman   sysctl: Separate ...
2
3
  #include <linux/stat.h>
  #include <linux/sysctl.h>
c59d87c46   Christoph Hellwig   xfs: remove subdi...
4
  #include "../fs/xfs/xfs_sysctl.h"
afa588b26   Eric W. Biederman   sysctl: Separate ...
5
6
  #include <linux/sunrpc/debug.h>
  #include <linux/string.h>
afa588b26   Eric W. Biederman   sysctl: Separate ...
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   Eric W. Biederman   sysctl: sysctl_bi...
15
  #include <linux/netdevice.h>
69e4469a3   Andy Shevchenko   sysctl: don't use...
16
  #include <linux/kernel.h>
ede9c2774   Andy Shevchenko   kernel/sysctl_bin...
17
  #include <linux/uuid.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
c5ddd2024   Al Viro   switch compat_sys...
19
  #include <linux/compat.h>
afa588b26   Eric W. Biederman   sysctl: Separate ...
20

26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
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   Eric W. Biederman   sysctl: Separate ...
23
  {
2830b6836   Eric W. Biederman   sysctl: Refactor ...
24
  	return -ENOSYS;
afa588b26   Eric W. Biederman   sysctl: Separate ...
25
  }
2830b6836   Eric W. Biederman   sysctl: Refactor ...
26
  static void deprecated_sysctl_warning(const int *name, int nlen)
afa588b26   Eric W. Biederman   sysctl: Separate ...
27
  {
afa588b26   Eric W. Biederman   sysctl: Separate ...
28
  	int i;
61cf69315   Andi Kleen   [sysctl] Fix brea...
29
30
31
32
  	/*
  	 * CTL_KERN/KERN_VERSION is used by older glibc and cannot
  	 * ever go away.
  	 */
9380fa60b   Mateusz Jurczyk   kernel/sysctl_bin...
33
  	if (nlen >= 2 && name[0] == CTL_KERN && name[1] == KERN_VERSION)
61cf69315   Andi Kleen   [sysctl] Fix brea...
34
  		return;
2fb10732c   Eric W. Biederman   sysctl: Warn abo...
35
  	if (printk_ratelimit()) {
afa588b26   Eric W. Biederman   sysctl: Separate ...
36
37
38
  		printk(KERN_INFO
  			"warning: process `%s' used the deprecated sysctl "
  			"system call with ", current->comm);
2830b6836   Eric W. Biederman   sysctl: Refactor ...
39
  		for (i = 0; i < nlen; i++)
7560ef39d   Tetsuo Handa   sysctl: add KERN_...
40
41
42
  			printk(KERN_CONT "%d.", name[i]);
  		printk(KERN_CONT "
  ");
afa588b26   Eric W. Biederman   sysctl: Separate ...
43
  	}
2830b6836   Eric W. Biederman   sysctl: Refactor ...
44
45
  	return;
  }
4440095c8   Andi Kleen   SYSCTL: Print bin...
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   Eric W. Biederman   sysctl: Reduce sy...
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   Eric W. Biederman   sysctl: Refactor ...
76
77
  {
  	int name[CTL_MAXNAME];
2830b6836   Eric W. Biederman   sysctl: Refactor ...
78
  	int i;
26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
79
80
  	/* Check args->nlen. */
  	if (nlen < 0 || nlen > CTL_MAXNAME)
2830b6836   Eric W. Biederman   sysctl: Refactor ...
81
  		return -ENOTDIR;
2830b6836   Eric W. Biederman   sysctl: Refactor ...
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   Andi Kleen   SYSCTL: Print bin...
86
  	warn_on_bintable(name, nlen);
2830b6836   Eric W. Biederman   sysctl: Refactor ...
87

26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
88
  	return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
2830b6836   Eric W. Biederman   sysctl: Refactor ...
89
  }
2830b6836   Eric W. Biederman   sysctl: Refactor ...
90
91
92
  SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
  {
  	struct __sysctl_args tmp;
26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
93
94
  	size_t oldlen = 0;
  	ssize_t result;
2830b6836   Eric W. Biederman   sysctl: Refactor ...
95
96
97
  
  	if (copy_from_user(&tmp, args, sizeof(tmp)))
  		return -EFAULT;
26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
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   Eric W. Biederman   sysctl: Refactor ...
111

26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
112
113
114
115
  	if (tmp.oldlenp && put_user(oldlen, tmp.oldlenp))
  		return -EFAULT;
  
  	return result;
afa588b26   Eric W. Biederman   sysctl: Separate ...
116
  }
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
117

26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
118

da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
119
  #ifdef CONFIG_COMPAT
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
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   Al Viro   switch compat_sys...
130
  COMPAT_SYSCALL_DEFINE1(sysctl, struct compat_sysctl_args __user *, args)
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
131
132
133
  {
  	struct compat_sysctl_args tmp;
  	compat_size_t __user *compat_oldlenp;
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
134
135
136
137
138
  	size_t oldlen = 0;
  	ssize_t result;
  
  	if (copy_from_user(&tmp, args, sizeof(tmp)))
  		return -EFAULT;
26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
139
140
  	if (tmp.oldval && !tmp.oldlenp)
  		return -EFAULT;
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
141

26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
142
143
144
  	compat_oldlenp = compat_ptr(tmp.oldlenp);
  	if (compat_oldlenp && get_user(oldlen, compat_oldlenp))
  		return -EFAULT;
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
145

da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
146
  	result = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
147
  			   compat_ptr(tmp.oldval), oldlen,
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
148
  			   compat_ptr(tmp.newval), tmp.newlen);
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
149

26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
150
151
152
  	if (result >= 0) {
  		oldlen = result;
  		result = 0;
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
153
  	}
26a7034b4   Eric W. Biederman   sysctl: Reduce sy...
154
155
  	if (compat_oldlenp && put_user(oldlen, compat_oldlenp))
  		return -EFAULT;
da3f6f9b3   Eric W. Biederman   sysctl: Introduce...
156
157
158
159
  	return result;
  }
  
  #endif /* CONFIG_COMPAT */