1/*	$NetBSD: linux_sysctl.c,v 1.48 2023/07/10 02:31:55 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2003, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Brown.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * sysctl system call.
34 */
35
36#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: linux_sysctl.c,v 1.48 2023/07/10 02:31:55 christos Exp $");
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/errno.h>
42#include <sys/proc.h>
43#include <sys/mount.h>
44#include <sys/sysctl.h>
45#include <sys/sched.h>
46#include <sys/syscallargs.h>
47#include <sys/ktrace.h>
48
49#include <compat/linux/common/linux_types.h>
50#include <compat/linux/common/linux_signal.h>
51#include <compat/linux/common/linux_ipc.h>
52#include <compat/linux/common/linux_sem.h>
53
54#include <compat/linux/linux_syscallargs.h>
55#include <compat/linux/common/linux_sysctl.h>
56#include <compat/linux/common/linux_exec.h>
57#include <compat/linux/common/linux_machdep.h>
58
59char linux_sysname[128] = "Linux";
60char linux_release[128] = "6.3.10";
61char linux_version[128] = "#1 SMP PREEMPT_DYNAMIC Wed Jun 28 18:34:30 UTC 2023";
62
63struct sysctlnode linux_sysctl_root = {
64	.sysctl_flags = SYSCTL_VERSION|
65	    CTLFLAG_ROOT|CTLTYPE_NODE|CTLFLAG_READWRITE,
66	.sysctl_num = 0,
67	.sysctl_name = "(linux_root)",
68	.sysctl_size = sizeof(struct sysctlnode),
69};
70
71extern int linux_enabled;
72
73/*
74 * We need an additional sysctllog here since each log can only
75 * deal with a single root node.
76 */
77
78static struct sysctllog *linux_clog;
79
80void
81linux_sysctl_fini(void)
82{
83
84	sysctl_teardown(&linux_clog);
85	sysctl_free(&linux_sysctl_root);
86}
87
88#if !defined(__aarch64__)
89
90SYSCTL_SETUP(linux_sysctl_setup, "linux emulation sysctls")
91{
92	const struct sysctlnode *node = &linux_sysctl_root;
93
94	sysctl_createv(&linux_clog, 0, &node, &node,
95		       CTLFLAG_PERMANENT,
96		       CTLTYPE_NODE, "kern", NULL,
97		       NULL, 0, NULL, 0,
98		       LINUX_CTL_KERN, CTL_EOL);
99	sysctl_createv(&linux_clog, 0, &node, NULL,
100		       CTLFLAG_PERMANENT,
101		       CTLTYPE_STRING, "ostype", NULL,
102		       NULL, 0, linux_sysname, sizeof(linux_sysname),
103		       LINUX_KERN_OSTYPE, CTL_EOL);
104	sysctl_createv(&linux_clog, 0, &node, NULL,
105		       CTLFLAG_PERMANENT,
106		       CTLTYPE_STRING, "osrelease", NULL,
107		       NULL, 0, linux_release, sizeof(linux_release),
108		       LINUX_KERN_OSRELEASE, CTL_EOL);
109	sysctl_createv(&linux_clog, 0, &node, NULL,
110		       CTLFLAG_PERMANENT,
111		       CTLTYPE_STRING, "version", NULL,
112		       NULL, 0, linux_version, sizeof(linux_version),
113		       LINUX_KERN_VERSION, CTL_EOL);
114
115	sysctl_createv(clog, 0, NULL, NULL,
116		       CTLFLAG_PERMANENT,
117		       CTLTYPE_NODE, "linux",
118		       SYSCTL_DESCR("Linux emulation settings"),
119		       NULL, 0, NULL, 0,
120		       CTL_EMUL, EMUL_LINUX, CTL_EOL);
121
122	sysctl_createv(clog, 0, NULL, NULL,
123		       CTLFLAG_PERMANENT,
124		       CTLTYPE_NODE, "kern",
125		       SYSCTL_DESCR("Linux kernel emulation settings"),
126		       NULL, 0, NULL, 0,
127		       CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN, CTL_EOL);
128	sysctl_createv(clog, 0, NULL, NULL,
129		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
130		       CTLTYPE_STRING, "ostype",
131		       SYSCTL_DESCR("Linux operating system type"),
132		       NULL, 0, linux_sysname, sizeof(linux_sysname),
133		       CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN,
134		       EMUL_LINUX_KERN_OSTYPE, CTL_EOL);
135	sysctl_createv(clog, 0, NULL, NULL,
136		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
137		       CTLTYPE_STRING, "osrelease",
138		       SYSCTL_DESCR("Linux operating system release"),
139		       NULL, 0, linux_release, sizeof(linux_release),
140		       CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN,
141		       EMUL_LINUX_KERN_OSRELEASE, CTL_EOL);
142	sysctl_createv(clog, 0, NULL, NULL,
143		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
144		       CTLTYPE_STRING, "osversion",
145		       SYSCTL_DESCR("Linux operating system revision"),
146		       NULL, 0, linux_version, sizeof(linux_version),
147		       CTL_EMUL, EMUL_LINUX, EMUL_LINUX_KERN,
148		       EMUL_LINUX_KERN_VERSION, CTL_EOL);
149
150	sysctl_createv(clog, 0, NULL, NULL,
151		       CTLFLAG_READWRITE,
152		       CTLTYPE_INT, "enabled",
153		       SYSCTL_DESCR("Linux compat enabled."),
154		       linux_sysctl_enable, 0, &linux_enabled, 0,
155		       CTL_EMUL, EMUL_LINUX, CTL_CREATE, CTL_EOL);
156
157	linux_sysctl_root.sysctl_flags &= ~CTLFLAG_READWRITE;
158}
159
160/*
161 * linux sysctl system call
162 */
163int
164linux_sys___sysctl(struct lwp *l, const struct linux_sys___sysctl_args *uap, register_t *retval)
165{
166	struct linux___sysctl ls;
167	int error, nerror, name[CTL_MAXNAME];
168	size_t savelen = 0, oldlen = 0;
169
170	/*
171	 * get linux args structure
172	 */
173	if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls))))
174		return error;
175
176	/*
177	 * get oldlen
178	 */
179	oldlen = 0;
180	if (ls.oldlenp != NULL) {
181		error = copyin(ls.oldlenp, &oldlen, sizeof(oldlen));
182		if (error)
183			return (error);
184	}
185	savelen = oldlen;
186
187	/*
188	 * top-level sysctl names may or may not be non-terminal, but
189	 * we don't care
190	 */
191	if (ls.nlen > CTL_MAXNAME || ls.nlen < 1)
192		return (ENOTDIR);
193	error = copyin(ls.name, &name, ls.nlen * sizeof(int));
194	if (error)
195		return (error);
196
197	ktrmib(name, ls.nlen);
198
199	/*
200	 * dispatch request into linux sysctl tree
201	 */
202	sysctl_lock(ls.newval != NULL);
203	error = sysctl_dispatch(&name[0], ls.nlen,
204				ls.oldval, &oldlen,
205				ls.newval, ls.newlen,
206				&name[0], l, &linux_sysctl_root);
207	sysctl_unlock();
208
209	/*
210	 * reset caller's oldlen, even if we got an error
211	 */
212	if (ls.oldlenp) {
213		nerror = copyout(&oldlen, ls.oldlenp, sizeof(oldlen));
214		if (error == 0)
215			error = nerror;
216	}
217
218	/*
219	 * if the only problem is that we weren't given enough space,
220	 * that's an ENOMEM error
221	 */
222	if (error == 0 && ls.oldval != NULL && savelen < oldlen)
223		error = ENOMEM;
224
225	return (error);
226}
227#endif
228