Skip to content

Commit 8fc344a

Browse files
committed
sysctl: Replace UINT converter macros with functions
Replace the SYSCTL_USER_TO_KERN_UINT_CONV and SYSCTL_UINT_CONV_CUSTOM macros with functions with the same logic. This makes debugging easier and aligns with the functions preference described in coding-style.rst. Update the only user of this API: pipe.c. Signed-off-by: Joel Granados <joel.granados@kernel.org>
1 parent 6036dc0 commit 8fc344a

3 files changed

Lines changed: 148 additions & 77 deletions

File tree

fs/pipe.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,10 +1481,24 @@ static struct file_system_type pipe_fs_type = {
14811481
};
14821482

14831483
#ifdef CONFIG_SYSCTL
1484-
static SYSCTL_USER_TO_KERN_UINT_CONV(_pipe_maxsz, round_pipe_size)
1485-
static SYSCTL_UINT_CONV_CUSTOM(_pipe_maxsz,
1486-
sysctl_user_to_kern_uint_conv_pipe_maxsz,
1487-
sysctl_kern_to_user_uint_conv, true)
1484+
1485+
static ulong round_pipe_size_ul(ulong size)
1486+
{
1487+
return round_pipe_size(size);
1488+
}
1489+
1490+
static int u2k_pipe_maxsz(const ulong *u_ptr, uint *k_ptr)
1491+
{
1492+
return proc_uint_u2k_conv_uop(u_ptr, k_ptr, round_pipe_size_ul);
1493+
}
1494+
1495+
static int do_proc_uint_conv_pipe_maxsz(ulong *u_ptr, uint *k_ptr,
1496+
int dir, const struct ctl_table *table)
1497+
{
1498+
return proc_uint_conv(u_ptr, k_ptr, dir, table, true,
1499+
u2k_pipe_maxsz,
1500+
proc_uint_k2u_conv);
1501+
}
14881502

14891503
static int proc_dopipe_max_size(const struct ctl_table *table, int write,
14901504
void *buffer, size_t *lenp, loff_t *ppos)

include/linux/sysctl.h

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -135,45 +135,6 @@ int do_proc_int_conv##name(bool *negp, unsigned long *u_ptr, int *k_ptr,\
135135
return user_to_kern(negp, u_ptr, k_ptr); \
136136
return 0; \
137137
}
138-
139-
#define SYSCTL_USER_TO_KERN_UINT_CONV(name, u_ptr_op) \
140-
int sysctl_user_to_kern_uint_conv##name(const unsigned long *u_ptr,\
141-
unsigned int *k_ptr) \
142-
{ \
143-
unsigned long u = u_ptr_op(*u_ptr); \
144-
if (u > UINT_MAX) \
145-
return -EINVAL; \
146-
WRITE_ONCE(*k_ptr, u); \
147-
return 0; \
148-
}
149-
150-
#define SYSCTL_UINT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \
151-
k_ptr_range_check) \
152-
int do_proc_uint_conv##name(unsigned long *u_ptr, unsigned int *k_ptr, \
153-
int dir, const struct ctl_table *tbl) \
154-
{ \
155-
if (SYSCTL_KERN_TO_USER(dir)) \
156-
return kern_to_user(u_ptr, k_ptr); \
157-
\
158-
if (k_ptr_range_check) { \
159-
unsigned int tmp_k; \
160-
int ret; \
161-
if (!tbl) \
162-
return -EINVAL; \
163-
ret = user_to_kern(u_ptr, &tmp_k); \
164-
if (ret) \
165-
return ret; \
166-
if ((tbl->extra1 && \
167-
*(unsigned int *)tbl->extra1 > tmp_k) || \
168-
(tbl->extra2 && \
169-
*(unsigned int *)tbl->extra2 < tmp_k)) \
170-
return -ERANGE; \
171-
WRITE_ONCE(*k_ptr, tmp_k); \
172-
} else \
173-
return user_to_kern(u_ptr, k_ptr); \
174-
return 0; \
175-
}
176-
177138
#else // CONFIG_PROC_SYSCTL
178139
#define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op) \
179140
int sysctl_user_to_kern_int_conv##name(const bool *negp, \
@@ -199,24 +160,8 @@ int do_proc_int_conv##name(bool *negp, unsigned long *u_ptr, int *k_ptr,\
199160
return -ENOSYS; \
200161
}
201162

202-
#define SYSCTL_USER_TO_KERN_UINT_CONV(name, u_ptr_op) \
203-
int sysctl_user_to_kern_uint_conv##name(const unsigned long *u_ptr,\
204-
unsigned int *k_ptr) \
205-
{ \
206-
return -ENOSYS; \
207-
}
208-
209-
#define SYSCTL_UINT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \
210-
k_ptr_range_check) \
211-
int do_proc_uint_conv##name(unsigned long *u_ptr, unsigned int *k_ptr, \
212-
int dir, const struct ctl_table *tbl) \
213-
{ \
214-
return -ENOSYS; \
215-
}
216-
217163
#endif // CONFIG_PROC_SYSCTL
218164

219-
220165
extern const unsigned long sysctl_long_vals[];
221166

222167
typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer,
@@ -239,6 +184,13 @@ int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer,
239184
size_t *lenp, loff_t *ppos,
240185
int (*conv)(unsigned long *lvalp, unsigned int *valp,
241186
int write, const struct ctl_table *table));
187+
int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr);
188+
int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
189+
ulong (*u_ptr_op)(const ulong));
190+
int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
191+
const struct ctl_table *tbl, bool k_ptr_range_check,
192+
int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr),
193+
int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr));
242194

243195
int proc_dou8vec_minmax(const struct ctl_table *table, int write, void *buffer,
244196
size_t *lenp, loff_t *ppos);
@@ -249,7 +201,6 @@ int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
249201
int proc_do_large_bitmap(const struct ctl_table *, int, void *, size_t *, loff_t *);
250202
int proc_do_static_key(const struct ctl_table *table, int write, void *buffer,
251203
size_t *lenp, loff_t *ppos);
252-
int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, const unsigned int *k_ptr);
253204

254205
/*
255206
* Register a set of sysctl names by calling register_sysctl

kernel/sysctl.c

Lines changed: 123 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -354,29 +354,117 @@ static void proc_put_char(void **buf, size_t *size, char c)
354354
}
355355
}
356356

357-
static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
358-
static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
359-
360-
static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
361-
sysctl_kern_to_user_int_conv, false)
362-
static SYSCTL_INT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_int_conv,
363-
sysctl_kern_to_user_int_conv, true)
357+
/**
358+
* proc_uint_u2k_conv_uop - Assign user value to a kernel pointer
359+
*
360+
* @u_ptr: pointer to user space variable
361+
* @k_ptr: pointer to kernel variable
362+
* @u_ptr_op: execute this function before assigning to k_ptr
363+
*
364+
* Uses WRITE_ONCE to assign value to k_ptr. Executes u_ptr_op if
365+
* not NULL. Check that the values are less than UINT_MAX to avoid
366+
* having to support wrap around from userspace.
367+
*
368+
* returns 0 on success.
369+
*/
370+
int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
371+
ulong (*u_ptr_op)(const ulong))
372+
{
373+
ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr;
364374

375+
if (u > UINT_MAX)
376+
return -EINVAL;
377+
WRITE_ONCE(*k_ptr, u);
378+
return 0;
379+
}
365380

366-
static SYSCTL_USER_TO_KERN_UINT_CONV(, SYSCTL_CONV_IDENTITY)
381+
/**
382+
* proc_uint_k2u_conv - Assign kernel value to a user space pointer
383+
*
384+
* @u_ptr: pointer to user space variable
385+
* @k_ptr: pointer to kernel variable
386+
*
387+
* Uses READ_ONCE to assign value to u_ptr.
388+
*
389+
* returns 0 on success.
390+
*/
391+
int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr)
392+
{
393+
uint val = READ_ONCE(*k_ptr);
394+
*u_ptr = (ulong)val;
395+
return 0;
396+
}
367397

368-
int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr,
369-
const unsigned int *k_ptr)
398+
/**
399+
* proc_uint_conv - Change user or kernel pointer based on direction
400+
*
401+
* @u_ptr: pointer to user variable
402+
* @k_ptr: pointer to kernel variable
403+
* @dir: %TRUE if this is a write to the sysctl file
404+
* @tbl: the sysctl table
405+
* @k_ptr_range_check: Check range for k_ptr when %TRUE
406+
* @user_to_kern: Callback used to assign value from user to kernel var
407+
* @kern_to_user: Callback used to assign value from kernel to user var
408+
*
409+
* When direction is kernel to user, then the u_ptr is modified.
410+
* When direction is user to kernel, then the k_ptr is modified.
411+
*
412+
* Returns 0 on success
413+
*/
414+
int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
415+
const struct ctl_table *tbl, bool k_ptr_range_check,
416+
int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr),
417+
int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr))
370418
{
371-
unsigned int val = READ_ONCE(*k_ptr);
372-
*u_ptr = (unsigned long)val;
419+
if (SYSCTL_KERN_TO_USER(dir))
420+
return kern_to_user(u_ptr, k_ptr);
421+
422+
if (k_ptr_range_check) {
423+
uint tmp_k;
424+
int ret;
425+
426+
if (!tbl)
427+
return -EINVAL;
428+
ret = user_to_kern(u_ptr, &tmp_k);
429+
if (ret)
430+
return ret;
431+
if ((tbl->extra1 &&
432+
*(uint *)tbl->extra1 > tmp_k) ||
433+
(tbl->extra2 &&
434+
*(uint *)tbl->extra2 < tmp_k))
435+
return -ERANGE;
436+
WRITE_ONCE(*k_ptr, tmp_k);
437+
} else
438+
return user_to_kern(u_ptr, k_ptr);
373439
return 0;
374440
}
375441

376-
static SYSCTL_UINT_CONV_CUSTOM(, sysctl_user_to_kern_uint_conv,
377-
sysctl_kern_to_user_uint_conv, false)
378-
static SYSCTL_UINT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_uint_conv,
379-
sysctl_kern_to_user_uint_conv, true)
442+
static int proc_uint_u2k_conv(const ulong *u_ptr, uint *k_ptr)
443+
{
444+
return proc_uint_u2k_conv_uop(u_ptr, k_ptr, NULL);
445+
}
446+
447+
static int do_proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
448+
const struct ctl_table *tbl)
449+
{
450+
return proc_uint_conv(u_ptr, k_ptr, dir, tbl, false,
451+
proc_uint_u2k_conv, proc_uint_k2u_conv);
452+
}
453+
454+
static int do_proc_uint_conv_minmax(ulong *u_ptr, uint *k_ptr, int dir,
455+
const struct ctl_table *tbl)
456+
{
457+
return proc_uint_conv(u_ptr, k_ptr, dir, tbl, true,
458+
proc_uint_u2k_conv, proc_uint_k2u_conv);
459+
}
460+
461+
static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
462+
static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
463+
464+
static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
465+
sysctl_kern_to_user_int_conv, false)
466+
static SYSCTL_INT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_int_conv,
467+
sysctl_kern_to_user_int_conv, true)
380468

381469
static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
382470

@@ -576,7 +664,6 @@ int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer,
576664
return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv);
577665
}
578666

579-
580667
/**
581668
* proc_dobool - read/write a bool
582669
* @table: the sysctl table
@@ -1079,6 +1166,25 @@ int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer,
10791166
return -ENOSYS;
10801167
}
10811168

1169+
int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr)
1170+
{
1171+
return -ENOSYS;
1172+
}
1173+
1174+
int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
1175+
ulong (*u_ptr_op)(const ulong))
1176+
{
1177+
return -ENOSYS;
1178+
}
1179+
1180+
int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
1181+
const struct ctl_table *tbl, bool k_ptr_range_check,
1182+
int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr),
1183+
int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr))
1184+
{
1185+
return -ENOSYS;
1186+
}
1187+
10821188
int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
10831189
void *buffer, size_t *lenp, loff_t *ppos)
10841190
{

0 commit comments

Comments
 (0)