linux/kernel/utsname_sysctl.c
<<
>>
Prefs
   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
  17static void *get_uts(struct ctl_table *table)
  18{
  19        char *which = table->data;
  20        struct uts_namespace *uts_ns;
  21
  22        uts_ns = current->nsproxy->uts_ns;
  23        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 */
  32static int proc_do_uts_string(struct ctl_table *table, int write,
  33                  void *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        memcpy(&uts_table, table, sizeof(uts_table));
  40        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        down_read(&uts_sem);
  49        memcpy(tmp_data, get_uts(table), sizeof(tmp_data));
  50        up_read(&uts_sem);
  51        r = proc_dostring(&uts_table, write, buffer, lenp, ppos);
  52
  53        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                down_write(&uts_sem);
  61                memcpy(get_uts(table), tmp_data, sizeof(tmp_data));
  62                up_write(&uts_sem);
  63                proc_sys_poll_notify(table->poll);
  64        }
  65
  66        return r;
  67}
  68#else
  69#define proc_do_uts_string NULL
  70#endif
  71
  72static DEFINE_CTL_TABLE_POLL(hostname_poll);
  73static DEFINE_CTL_TABLE_POLL(domainname_poll);
  74
  75static 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
 116static 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 */
 130void uts_proc_notify(enum uts_proc proc)
 131{
 132        struct ctl_table *table = &uts_kern_table[proc];
 133
 134        proc_sys_poll_notify(table->poll);
 135}
 136#endif
 137
 138static int __init utsname_sysctl_init(void)
 139{
 140        register_sysctl_table(uts_root_table);
 141        return 0;
 142}
 143
 144device_initcall(utsname_sysctl_init);
 145