|
@@ -38,6 +38,12 @@ unsigned int pipe_max_size = 1048576;
|
|
|
*/
|
|
|
unsigned int pipe_min_size = PAGE_SIZE;
|
|
|
|
|
|
+/* Maximum allocatable pages per user. Hard limit is unset by default, soft
|
|
|
+ * matches default values.
|
|
|
+ */
|
|
|
+unsigned long pipe_user_pages_hard;
|
|
|
+unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR;
|
|
|
+
|
|
|
/*
|
|
|
* We use a start+len construction, which provides full use of the
|
|
|
* allocated memory.
|
|
@@ -583,20 +589,49 @@ pipe_fasync(int fd, struct file *filp, int on)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+static void account_pipe_buffers(struct pipe_inode_info *pipe,
|
|
|
+ unsigned long old, unsigned long new)
|
|
|
+{
|
|
|
+ atomic_long_add(new - old, &pipe->user->pipe_bufs);
|
|
|
+}
|
|
|
+
|
|
|
+static bool too_many_pipe_buffers_soft(struct user_struct *user)
|
|
|
+{
|
|
|
+ return pipe_user_pages_soft &&
|
|
|
+ atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_soft;
|
|
|
+}
|
|
|
+
|
|
|
+static bool too_many_pipe_buffers_hard(struct user_struct *user)
|
|
|
+{
|
|
|
+ return pipe_user_pages_hard &&
|
|
|
+ atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_hard;
|
|
|
+}
|
|
|
+
|
|
|
struct pipe_inode_info *alloc_pipe_info(void)
|
|
|
{
|
|
|
struct pipe_inode_info *pipe;
|
|
|
|
|
|
pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
|
|
|
if (pipe) {
|
|
|
- pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL);
|
|
|
+ unsigned long pipe_bufs = PIPE_DEF_BUFFERS;
|
|
|
+ struct user_struct *user = get_current_user();
|
|
|
+
|
|
|
+ if (!too_many_pipe_buffers_hard(user)) {
|
|
|
+ if (too_many_pipe_buffers_soft(user))
|
|
|
+ pipe_bufs = 1;
|
|
|
+ pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL);
|
|
|
+ }
|
|
|
+
|
|
|
if (pipe->bufs) {
|
|
|
init_waitqueue_head(&pipe->wait);
|
|
|
pipe->r_counter = pipe->w_counter = 1;
|
|
|
- pipe->buffers = PIPE_DEF_BUFFERS;
|
|
|
+ pipe->buffers = pipe_bufs;
|
|
|
+ pipe->user = user;
|
|
|
+ account_pipe_buffers(pipe, 0, pipe_bufs);
|
|
|
mutex_init(&pipe->mutex);
|
|
|
return pipe;
|
|
|
}
|
|
|
+ free_uid(user);
|
|
|
kfree(pipe);
|
|
|
}
|
|
|
|
|
@@ -607,6 +642,8 @@ void free_pipe_info(struct pipe_inode_info *pipe)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
+ account_pipe_buffers(pipe, pipe->buffers, 0);
|
|
|
+ free_uid(pipe->user);
|
|
|
for (i = 0; i < pipe->buffers; i++) {
|
|
|
struct pipe_buffer *buf = pipe->bufs + i;
|
|
|
if (buf->ops)
|
|
@@ -998,6 +1035,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
|
|
|
memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer));
|
|
|
}
|
|
|
|
|
|
+ account_pipe_buffers(pipe, pipe->buffers, nr_pages);
|
|
|
pipe->curbuf = 0;
|
|
|
kfree(pipe->bufs);
|
|
|
pipe->bufs = bufs;
|
|
@@ -1069,6 +1107,11 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) {
|
|
|
ret = -EPERM;
|
|
|
goto out;
|
|
|
+ } else if ((too_many_pipe_buffers_hard(pipe->user) ||
|
|
|
+ too_many_pipe_buffers_soft(pipe->user)) &&
|
|
|
+ !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
|
|
|
+ ret = -EPERM;
|
|
|
+ goto out;
|
|
|
}
|
|
|
ret = pipe_set_size(pipe, nr_pages);
|
|
|
break;
|