1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2007
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Eric Biederman <ebiederm@xmision.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/export.h>
9*4882a593Smuzhiyun #include <linux/uts.h>
10*4882a593Smuzhiyun #include <linux/utsname.h>
11*4882a593Smuzhiyun #include <linux/sysctl.h>
12*4882a593Smuzhiyun #include <linux/wait.h>
13*4882a593Smuzhiyun #include <linux/rwsem.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #ifdef CONFIG_PROC_SYSCTL
16*4882a593Smuzhiyun
get_uts(struct ctl_table * table)17*4882a593Smuzhiyun static void *get_uts(struct ctl_table *table)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun char *which = table->data;
20*4882a593Smuzhiyun struct uts_namespace *uts_ns;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun uts_ns = current->nsproxy->uts_ns;
23*4882a593Smuzhiyun which = (which - (char *)&init_uts_ns) + (char *)uts_ns;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun return which;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun * Special case of dostring for the UTS structure. This has locks
30*4882a593Smuzhiyun * to observe. Should this be in kernel/sys.c ????
31*4882a593Smuzhiyun */
proc_do_uts_string(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)32*4882a593Smuzhiyun static int proc_do_uts_string(struct ctl_table *table, int write,
33*4882a593Smuzhiyun void *buffer, size_t *lenp, loff_t *ppos)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun struct ctl_table uts_table;
36*4882a593Smuzhiyun int r;
37*4882a593Smuzhiyun char tmp_data[__NEW_UTS_LEN + 1];
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun memcpy(&uts_table, table, sizeof(uts_table));
40*4882a593Smuzhiyun uts_table.data = tmp_data;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun * Buffer the value in tmp_data so that proc_dostring() can be called
44*4882a593Smuzhiyun * without holding any locks.
45*4882a593Smuzhiyun * We also need to read the original value in the write==1 case to
46*4882a593Smuzhiyun * support partial writes.
47*4882a593Smuzhiyun */
48*4882a593Smuzhiyun down_read(&uts_sem);
49*4882a593Smuzhiyun memcpy(tmp_data, get_uts(table), sizeof(tmp_data));
50*4882a593Smuzhiyun up_read(&uts_sem);
51*4882a593Smuzhiyun r = proc_dostring(&uts_table, write, buffer, lenp, ppos);
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun if (write) {
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun * Write back the new value.
56*4882a593Smuzhiyun * Note that, since we dropped uts_sem, the result can
57*4882a593Smuzhiyun * theoretically be incorrect if there are two parallel writes
58*4882a593Smuzhiyun * at non-zero offsets to the same sysctl.
59*4882a593Smuzhiyun */
60*4882a593Smuzhiyun down_write(&uts_sem);
61*4882a593Smuzhiyun memcpy(get_uts(table), tmp_data, sizeof(tmp_data));
62*4882a593Smuzhiyun up_write(&uts_sem);
63*4882a593Smuzhiyun proc_sys_poll_notify(table->poll);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun return r;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun #else
69*4882a593Smuzhiyun #define proc_do_uts_string NULL
70*4882a593Smuzhiyun #endif
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static DEFINE_CTL_TABLE_POLL(hostname_poll);
73*4882a593Smuzhiyun static DEFINE_CTL_TABLE_POLL(domainname_poll);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun static struct ctl_table uts_kern_table[] = {
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun .procname = "ostype",
78*4882a593Smuzhiyun .data = init_uts_ns.name.sysname,
79*4882a593Smuzhiyun .maxlen = sizeof(init_uts_ns.name.sysname),
80*4882a593Smuzhiyun .mode = 0444,
81*4882a593Smuzhiyun .proc_handler = proc_do_uts_string,
82*4882a593Smuzhiyun },
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun .procname = "osrelease",
85*4882a593Smuzhiyun .data = init_uts_ns.name.release,
86*4882a593Smuzhiyun .maxlen = sizeof(init_uts_ns.name.release),
87*4882a593Smuzhiyun .mode = 0444,
88*4882a593Smuzhiyun .proc_handler = proc_do_uts_string,
89*4882a593Smuzhiyun },
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun .procname = "version",
92*4882a593Smuzhiyun .data = init_uts_ns.name.version,
93*4882a593Smuzhiyun .maxlen = sizeof(init_uts_ns.name.version),
94*4882a593Smuzhiyun .mode = 0444,
95*4882a593Smuzhiyun .proc_handler = proc_do_uts_string,
96*4882a593Smuzhiyun },
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun .procname = "hostname",
99*4882a593Smuzhiyun .data = init_uts_ns.name.nodename,
100*4882a593Smuzhiyun .maxlen = sizeof(init_uts_ns.name.nodename),
101*4882a593Smuzhiyun .mode = 0644,
102*4882a593Smuzhiyun .proc_handler = proc_do_uts_string,
103*4882a593Smuzhiyun .poll = &hostname_poll,
104*4882a593Smuzhiyun },
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun .procname = "domainname",
107*4882a593Smuzhiyun .data = init_uts_ns.name.domainname,
108*4882a593Smuzhiyun .maxlen = sizeof(init_uts_ns.name.domainname),
109*4882a593Smuzhiyun .mode = 0644,
110*4882a593Smuzhiyun .proc_handler = proc_do_uts_string,
111*4882a593Smuzhiyun .poll = &domainname_poll,
112*4882a593Smuzhiyun },
113*4882a593Smuzhiyun {}
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static struct ctl_table uts_root_table[] = {
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun .procname = "kernel",
119*4882a593Smuzhiyun .mode = 0555,
120*4882a593Smuzhiyun .child = uts_kern_table,
121*4882a593Smuzhiyun },
122*4882a593Smuzhiyun {}
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun #ifdef CONFIG_PROC_SYSCTL
126*4882a593Smuzhiyun /*
127*4882a593Smuzhiyun * Notify userspace about a change in a certain entry of uts_kern_table,
128*4882a593Smuzhiyun * identified by the parameter proc.
129*4882a593Smuzhiyun */
uts_proc_notify(enum uts_proc proc)130*4882a593Smuzhiyun void uts_proc_notify(enum uts_proc proc)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct ctl_table *table = &uts_kern_table[proc];
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun proc_sys_poll_notify(table->poll);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun #endif
137*4882a593Smuzhiyun
utsname_sysctl_init(void)138*4882a593Smuzhiyun static int __init utsname_sysctl_init(void)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun register_sysctl_table(uts_root_table);
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun device_initcall(utsname_sysctl_init);
145