diff options
Diffstat (limited to 'fs/pipe.c')
-rw-r--r-- | fs/pipe.c | 41 |
1 files changed, 31 insertions, 10 deletions
@@ -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 | |||
1104 | out_revert_acct: | ||
1105 | account_pipe_buffers(pipe->user, nr_pages, pipe->buffers); | ||
1106 | return ret; | ||
1086 | } | 1107 | } |
1087 | 1108 | ||
1088 | /* | 1109 | /* |