Files
Christoph Hellwig e13d6f5008 BACKPORT: sysctl: pass kernel pointers to ->proc_handler
Instead of having all the sysctl handlers deal with user pointers, which
is rather hairy in terms of the BPF interaction, copy the input to and
from  userspace in common code.  This also means that the strings are
always NUL-terminated by the common code, making the API a little bit
safer.

As most handler just pass through the data to one of the common handlers
a lot of the changes are mechnical.

Change-Id: Ic71fd778e4cea58adc51d634d9e53c1f9f90cdf2
Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2025-09-20 03:21:20 +01:00

110 lines
2.8 KiB
C

/*
* File: sysctl.c
*
* Phonet /proc/sys/net/phonet interface implementation
*
* Copyright (C) 2008 Nokia Corporation.
*
* Author: Rémi Denis-Courmont
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <linux/seqlock.h>
#include <linux/sysctl.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <net/sock.h>
#include <linux/phonet.h>
#include <net/phonet/phonet.h>
#define DYNAMIC_PORT_MIN 0x40
#define DYNAMIC_PORT_MAX 0x7f
static DEFINE_SEQLOCK(local_port_range_lock);
static int local_port_range_min[2] = {0, 0};
static int local_port_range_max[2] = {1023, 1023};
static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
static struct ctl_table_header *phonet_table_hrd;
static void set_local_port_range(int range[2])
{
write_seqlock(&local_port_range_lock);
local_port_range[0] = range[0];
local_port_range[1] = range[1];
write_sequnlock(&local_port_range_lock);
}
void phonet_get_local_port_range(int *min, int *max)
{
unsigned int seq;
do {
seq = read_seqbegin(&local_port_range_lock);
if (min)
*min = local_port_range[0];
if (max)
*max = local_port_range[1];
} while (read_seqretry(&local_port_range_lock, seq));
}
static int proc_local_port_range(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
int ret;
int range[2] = {local_port_range[0], local_port_range[1]};
struct ctl_table tmp = {
.data = &range,
.maxlen = sizeof(range),
.mode = table->mode,
.extra1 = &local_port_range_min,
.extra2 = &local_port_range_max,
};
ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
if (write && ret == 0) {
if (range[1] < range[0])
ret = -EINVAL;
else
set_local_port_range(range);
}
return ret;
}
static struct ctl_table phonet_table[] = {
{
.procname = "local_port_range",
.data = &local_port_range,
.maxlen = sizeof(local_port_range),
.mode = 0644,
.proc_handler = proc_local_port_range,
},
{ }
};
int __init phonet_sysctl_init(void)
{
phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table);
return phonet_table_hrd == NULL ? -ENOMEM : 0;
}
void phonet_sysctl_exit(void)
{
unregister_net_sysctl_table(phonet_table_hrd);
}