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