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