pipe_max_size is assigned directly via procfs sysctl:
static struct ctl_table fs_table[] = {
...
{
.procname = "pipe-max-size",
.data = &pipe_max_size,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &pipe_proc_fn,
.extra1 = &pipe_min_size,
},
...
int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
size_t *lenp, loff_t *ppos)
{
...
ret = proc_dointvec_minmax(table, write, buf, lenp, ppos)
...
and then later rounded in-place a few statements later:
...
pipe_max_size = round_pipe_size(pipe_max_size);
...
This leaves a window of time between initial assignment and rounding
that may be visible to other threads. (For example, one thread sets a non-rounded value to pipe_max_size while another reads its value.)
Similar reads of pipe_max_size are potentially racey:
pipe.c :: alloc_pipe_info()
pipe.c :: pipe_set_size()
Add a new proc_dopipe_max_size() function that consolidates reading the
new value from the user buffer, verifying bounds, and calling
round_pipe_size() with a single assignment to pipe_max_size.
Reported-by: Mikulas Patocka <
mpatocka@redhat.com>
Signed-off-by: Joe Lawrence <
joe.lawrence@redhat.com>
---
v2:
- Fix !CONFIG_PROC_SYSCTL build case
fs/pipe.c | 16 ++--------------
include/linux/pipe_fs_i.h | 1 +
include/linux/sysctl.h | 3 +++
kernel/sysctl.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 55 insertions(+), 14 deletions(-)
diff --git a/fs/pipe.c b/fs/pipe.c
index 8cbc97d97753..4db3cd2d139c 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1019,7 +1019,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
* Currently we rely on the pipe array holding a power-of-2 number
* of pages. Returns 0 on error.
*/
-static inline unsigned int round_pipe_size(unsigned int size)
+unsigned int round_pipe_size(unsigned int size)
{
unsigned long nr_pages;
@@ -1130,19 +1130,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
size_t *lenp, loff_t *ppos)
{
- unsigned int rounded_pipe_max_size;
- int ret;