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