aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/pipe.c')
-rw-r--r--fs/pipe.c41
1 files changed, 31 insertions, 10 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index b9422bc17028..dc5f4c040890 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1027,6 +1027,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
1027{ 1027{
1028 struct pipe_buffer *bufs; 1028 struct pipe_buffer *bufs;
1029 unsigned int size, nr_pages; 1029 unsigned int size, nr_pages;
1030 long ret = 0;
1030 1031
1031 size = round_pipe_size(arg); 1032 size = round_pipe_size(arg);
1032 nr_pages = size >> PAGE_SHIFT; 1033 nr_pages = size >> PAGE_SHIFT;
@@ -1034,13 +1035,26 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
1034 if (!nr_pages) 1035 if (!nr_pages)
1035 return -EINVAL; 1036 return -EINVAL;
1036 1037
1037 if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) 1038 /*
1039 * If trying to increase the pipe capacity, check that an
1040 * unprivileged user is not trying to exceed various limits
1041 * (soft limit check here, hard limit check just below).
1042 * Decreasing the pipe capacity is always permitted, even
1043 * if the user is currently over a limit.
1044 */
1045 if (nr_pages > pipe->buffers &&
1046 size > pipe_max_size && !capable(CAP_SYS_RESOURCE))
1038 return -EPERM; 1047 return -EPERM;
1039 1048
1040 if ((too_many_pipe_buffers_hard(pipe->user) || 1049 account_pipe_buffers(pipe->user, pipe->buffers, nr_pages);
1041 too_many_pipe_buffers_soft(pipe->user)) && 1050
1042 !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) 1051 if (nr_pages > pipe->buffers &&
1043 return -EPERM; 1052 (too_many_pipe_buffers_hard(pipe->user) ||
1053 too_many_pipe_buffers_soft(pipe->user)) &&
1054 !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
1055 ret = -EPERM;
1056 goto out_revert_acct;
1057 }
1044 1058
1045 /* 1059 /*
1046 * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't 1060 * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't
@@ -1048,13 +1062,17 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
1048 * again like we would do for growing. If the pipe currently 1062 * again like we would do for growing. If the pipe currently
1049 * contains more buffers than arg, then return busy. 1063 * contains more buffers than arg, then return busy.
1050 */ 1064 */
1051 if (nr_pages < pipe->nrbufs) 1065 if (nr_pages < pipe->nrbufs) {
1052 return -EBUSY; 1066 ret = -EBUSY;
1067 goto out_revert_acct;
1068 }
1053 1069
1054 bufs = kcalloc(nr_pages, sizeof(*bufs), 1070 bufs = kcalloc(nr_pages, sizeof(*bufs),
1055 GFP_KERNEL_ACCOUNT | __GFP_NOWARN); 1071 GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
1056 if (unlikely(!bufs)) 1072 if (unlikely(!bufs)) {
1057 return -ENOMEM; 1073 ret = -ENOMEM;
1074 goto out_revert_acct;
1075 }
1058 1076
1059 /* 1077 /*
1060 * The pipe array wraps around, so just start the new one at zero 1078 * The pipe array wraps around, so just start the new one at zero
@@ -1077,12 +1095,15 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
1077 memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); 1095 memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer));
1078 } 1096 }
1079 1097
1080 account_pipe_buffers(pipe->user, pipe->buffers, nr_pages);
1081 pipe->curbuf = 0; 1098 pipe->curbuf = 0;
1082 kfree(pipe->bufs); 1099 kfree(pipe->bufs);
1083 pipe->bufs = bufs; 1100 pipe->bufs = bufs;
1084 pipe->buffers = nr_pages; 1101 pipe->buffers = nr_pages;
1085 return nr_pages * PAGE_SIZE; 1102 return nr_pages * PAGE_SIZE;
1103
1104out_revert_acct:
1105 account_pipe_buffers(pipe->user, nr_pages, pipe->buffers);
1106 return ret;
1086} 1107}
1087 1108
1088/* 1109/*