blob: 7d550cc76a3bd3b8f205992ad4fe7fd08af18ded [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Eric W. Biedermanafa588b2009-04-02 23:44:59 -07002#include <linux/stat.h>
3#include <linux/sysctl.h>
Christoph Hellwigc59d87c2011-08-12 16:21:35 -05004#include "../fs/xfs/xfs_sysctl.h"
Eric W. Biedermanafa588b2009-04-02 23:44:59 -07005#include <linux/sunrpc/debug.h>
6#include <linux/string.h>
Eric W. Biedermanafa588b2009-04-02 23:44:59 -07007#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>
Eric W. Biederman63395b62009-11-12 00:35:55 -080015#include <linux/netdevice.h>
Andy Shevchenko69e44692010-05-24 14:33:26 -070016#include <linux/kernel.h>
Andy Shevchenkoede9c2772016-05-20 17:01:10 -070017#include <linux/uuid.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
Al Viroc5ddd202013-03-19 14:25:51 -040019#include <linux/compat.h>
Eric W. Biedermanafa588b2009-04-02 23:44:59 -070020
Eric W. Biederman26a70342009-11-05 05:26:41 -080021static ssize_t binary_sysctl(const int *name, int nlen,
22 void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
Eric W. Biedermanafa588b2009-04-02 23:44:59 -070023{
Eric W. Biederman2830b682009-04-03 00:09:33 -070024 return -ENOSYS;
Eric W. Biedermanafa588b2009-04-02 23:44:59 -070025}
26
Eric W. Biederman2830b682009-04-03 00:09:33 -070027static void deprecated_sysctl_warning(const int *name, int nlen)
Eric W. Biedermanafa588b2009-04-02 23:44:59 -070028{
Eric W. Biedermanafa588b2009-04-02 23:44:59 -070029 int i;
30
Andi Kleen61cf69312009-12-16 12:28:44 +010031 /*
32 * CTL_KERN/KERN_VERSION is used by older glibc and cannot
33 * ever go away.
34 */
Mateusz Jurczyk9380fa62017-07-12 14:34:01 -070035 if (nlen >= 2 && name[0] == CTL_KERN && name[1] == KERN_VERSION)
Andi Kleen61cf69312009-12-16 12:28:44 +010036 return;
37
Eric W. Biederman2fb107322009-11-11 19:32:48 -080038 if (printk_ratelimit()) {
Eric W. Biedermanafa588b2009-04-02 23:44:59 -070039 printk(KERN_INFO
40 "warning: process `%s' used the deprecated sysctl "
41 "system call with ", current->comm);
Eric W. Biederman2830b682009-04-03 00:09:33 -070042 for (i = 0; i < nlen; i++)
Tetsuo Handa7560ef32016-12-14 15:04:26 -080043 printk(KERN_CONT "%d.", name[i]);
44 printk(KERN_CONT "\n");
Eric W. Biedermanafa588b2009-04-02 23:44:59 -070045 }
Eric W. Biederman2830b682009-04-03 00:09:33 -070046 return;
47}
48
Andi Kleen44400952009-12-23 21:00:20 +010049#define WARN_ONCE_HASH_BITS 8
50#define WARN_ONCE_HASH_SIZE (1<<WARN_ONCE_HASH_BITS)
51
52static 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 */
65static void warn_on_bintable(const int *name, int nlen)
66{
67 int i;
68 u32 hash = FNV32_OFFSET;
69
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))
74 return;
75 deprecated_sysctl_warning(name, nlen);
76}
77
Eric W. Biederman26a70342009-11-05 05:26:41 -080078static ssize_t do_sysctl(int __user *args_name, int nlen,
79 void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
Eric W. Biederman2830b682009-04-03 00:09:33 -070080{
81 int name[CTL_MAXNAME];
Eric W. Biederman2830b682009-04-03 00:09:33 -070082 int i;
83
Eric W. Biederman26a70342009-11-05 05:26:41 -080084 /* Check args->nlen. */
85 if (nlen < 0 || nlen > CTL_MAXNAME)
Eric W. Biederman2830b682009-04-03 00:09:33 -070086 return -ENOTDIR;
Eric W. Biederman2830b682009-04-03 00:09:33 -070087 /* 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
Andi Kleen44400952009-12-23 21:00:20 +010092 warn_on_bintable(name, nlen);
Eric W. Biederman2830b682009-04-03 00:09:33 -070093
Eric W. Biederman26a70342009-11-05 05:26:41 -080094 return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
Eric W. Biederman2830b682009-04-03 00:09:33 -070095}
96
Eric W. Biederman2830b682009-04-03 00:09:33 -070097SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
98{
99 struct __sysctl_args tmp;
Eric W. Biederman26a70342009-11-05 05:26:41 -0800100 size_t oldlen = 0;
101 ssize_t result;
Eric W. Biederman2830b682009-04-03 00:09:33 -0700102
103 if (copy_from_user(&tmp, args, sizeof(tmp)))
104 return -EFAULT;
105
Eric W. Biederman26a70342009-11-05 05:26:41 -0800106 if (tmp.oldval && !tmp.oldlenp)
107 return -EFAULT;
Eric W. Biederman2830b682009-04-03 00:09:33 -0700108
Eric W. Biederman26a70342009-11-05 05:26:41 -0800109 if (tmp.oldlenp && get_user(oldlen, tmp.oldlenp))
110 return -EFAULT;
111
112 result = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, oldlen,
113 tmp.newval, tmp.newlen);
114
115 if (result >= 0) {
116 oldlen = result;
117 result = 0;
118 }
119
120 if (tmp.oldlenp && put_user(oldlen, tmp.oldlenp))
121 return -EFAULT;
122
123 return result;
Eric W. Biedermanafa588b2009-04-02 23:44:59 -0700124}
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700125
Eric W. Biederman26a70342009-11-05 05:26:41 -0800126
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700127#ifdef CONFIG_COMPAT
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700128
129struct 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
Al Viroc5ddd202013-03-19 14:25:51 -0400139COMPAT_SYSCALL_DEFINE1(sysctl, struct compat_sysctl_args __user *, args)
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700140{
141 struct compat_sysctl_args tmp;
142 compat_size_t __user *compat_oldlenp;
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700143 size_t oldlen = 0;
144 ssize_t result;
145
146 if (copy_from_user(&tmp, args, sizeof(tmp)))
147 return -EFAULT;
148
Eric W. Biederman26a70342009-11-05 05:26:41 -0800149 if (tmp.oldval && !tmp.oldlenp)
150 return -EFAULT;
151
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700152 compat_oldlenp = compat_ptr(tmp.oldlenp);
Eric W. Biederman26a70342009-11-05 05:26:41 -0800153 if (compat_oldlenp && get_user(oldlen, compat_oldlenp))
154 return -EFAULT;
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700155
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700156 result = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
Eric W. Biederman26a70342009-11-05 05:26:41 -0800157 compat_ptr(tmp.oldval), oldlen,
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700158 compat_ptr(tmp.newval), tmp.newlen);
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700159
Eric W. Biederman26a70342009-11-05 05:26:41 -0800160 if (result >= 0) {
161 oldlen = result;
162 result = 0;
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700163 }
164
Eric W. Biederman26a70342009-11-05 05:26:41 -0800165 if (compat_oldlenp && put_user(oldlen, compat_oldlenp))
166 return -EFAULT;
167
Eric W. Biedermanda3f6f92009-04-03 00:36:27 -0700168 return result;
169}
170
171#endif /* CONFIG_COMPAT */