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