diff options
Diffstat (limited to 'fs/pipe.c')
-rw-r--r-- | fs/pipe.c | 77 |
1 files changed, 53 insertions, 24 deletions
@@ -26,9 +26,14 @@ | |||
26 | 26 | ||
27 | /* | 27 | /* |
28 | * The max size that a non-root user is allowed to grow the pipe. Can | 28 | * The max size that a non-root user is allowed to grow the pipe. Can |
29 | * be set by root in /proc/sys/fs/pipe-max-pages | 29 | * be set by root in /proc/sys/fs/pipe-max-size |
30 | */ | 30 | */ |
31 | unsigned int pipe_max_pages = PIPE_DEF_BUFFERS * 16; | 31 | unsigned int pipe_max_size = 1048576; |
32 | |||
33 | /* | ||
34 | * Minimum pipe size, as required by POSIX | ||
35 | */ | ||
36 | unsigned int pipe_min_size = PAGE_SIZE; | ||
32 | 37 | ||
33 | /* | 38 | /* |
34 | * We use a start+len construction, which provides full use of the | 39 | * We use a start+len construction, which provides full use of the |
@@ -1118,26 +1123,20 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes) | |||
1118 | * Allocate a new array of pipe buffers and copy the info over. Returns the | 1123 | * Allocate a new array of pipe buffers and copy the info over. Returns the |
1119 | * pipe size if successful, or return -ERROR on error. | 1124 | * pipe size if successful, or return -ERROR on error. |
1120 | */ | 1125 | */ |
1121 | static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) | 1126 | static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) |
1122 | { | 1127 | { |
1123 | struct pipe_buffer *bufs; | 1128 | struct pipe_buffer *bufs; |
1124 | 1129 | ||
1125 | /* | 1130 | /* |
1126 | * Must be a power-of-2 currently | ||
1127 | */ | ||
1128 | if (!is_power_of_2(arg)) | ||
1129 | return -EINVAL; | ||
1130 | |||
1131 | /* | ||
1132 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't | 1131 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't |
1133 | * expect a lot of shrink+grow operations, just free and allocate | 1132 | * expect a lot of shrink+grow operations, just free and allocate |
1134 | * again like we would do for growing. If the pipe currently | 1133 | * again like we would do for growing. If the pipe currently |
1135 | * contains more buffers than arg, then return busy. | 1134 | * contains more buffers than arg, then return busy. |
1136 | */ | 1135 | */ |
1137 | if (arg < pipe->nrbufs) | 1136 | if (nr_pages < pipe->nrbufs) |
1138 | return -EBUSY; | 1137 | return -EBUSY; |
1139 | 1138 | ||
1140 | bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL); | 1139 | bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL); |
1141 | if (unlikely(!bufs)) | 1140 | if (unlikely(!bufs)) |
1142 | return -ENOMEM; | 1141 | return -ENOMEM; |
1143 | 1142 | ||
@@ -1158,8 +1157,37 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) | |||
1158 | pipe->curbuf = 0; | 1157 | pipe->curbuf = 0; |
1159 | kfree(pipe->bufs); | 1158 | kfree(pipe->bufs); |
1160 | pipe->bufs = bufs; | 1159 | pipe->bufs = bufs; |
1161 | pipe->buffers = arg; | 1160 | pipe->buffers = nr_pages; |
1162 | return arg; | 1161 | return nr_pages * PAGE_SIZE; |
1162 | } | ||
1163 | |||
1164 | /* | ||
1165 | * Currently we rely on the pipe array holding a power-of-2 number | ||
1166 | * of pages. | ||
1167 | */ | ||
1168 | static inline unsigned int round_pipe_size(unsigned int size) | ||
1169 | { | ||
1170 | unsigned long nr_pages; | ||
1171 | |||
1172 | nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
1173 | return roundup_pow_of_two(nr_pages) << PAGE_SHIFT; | ||
1174 | } | ||
1175 | |||
1176 | /* | ||
1177 | * This should work even if CONFIG_PROC_FS isn't set, as proc_dointvec_minmax | ||
1178 | * will return an error. | ||
1179 | */ | ||
1180 | int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf, | ||
1181 | size_t *lenp, loff_t *ppos) | ||
1182 | { | ||
1183 | int ret; | ||
1184 | |||
1185 | ret = proc_dointvec_minmax(table, write, buf, lenp, ppos); | ||
1186 | if (ret < 0 || !write) | ||
1187 | return ret; | ||
1188 | |||
1189 | pipe_max_size = round_pipe_size(pipe_max_size); | ||
1190 | return ret; | ||
1163 | } | 1191 | } |
1164 | 1192 | ||
1165 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | 1193 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) |
@@ -1174,23 +1202,24 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1174 | mutex_lock(&pipe->inode->i_mutex); | 1202 | mutex_lock(&pipe->inode->i_mutex); |
1175 | 1203 | ||
1176 | switch (cmd) { | 1204 | switch (cmd) { |
1177 | case F_SETPIPE_SZ: | 1205 | case F_SETPIPE_SZ: { |
1178 | if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) { | 1206 | unsigned int size, nr_pages; |
1179 | ret = -EINVAL; | 1207 | |
1208 | size = round_pipe_size(arg); | ||
1209 | nr_pages = size >> PAGE_SHIFT; | ||
1210 | |||
1211 | if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { | ||
1212 | ret = -EPERM; | ||
1180 | goto out; | 1213 | goto out; |
1181 | } | 1214 | } else if (nr_pages < PAGE_SIZE) { |
1182 | /* | ||
1183 | * The pipe needs to be at least 2 pages large to | ||
1184 | * guarantee POSIX behaviour. | ||
1185 | */ | ||
1186 | if (arg < 2) { | ||
1187 | ret = -EINVAL; | 1215 | ret = -EINVAL; |
1188 | goto out; | 1216 | goto out; |
1189 | } | 1217 | } |
1190 | ret = pipe_set_size(pipe, arg); | 1218 | ret = pipe_set_size(pipe, nr_pages); |
1191 | break; | 1219 | break; |
1220 | } | ||
1192 | case F_GETPIPE_SZ: | 1221 | case F_GETPIPE_SZ: |
1193 | ret = pipe->buffers; | 1222 | ret = pipe->buffers * PAGE_SIZE; |
1194 | break; | 1223 | break; |
1195 | default: | 1224 | default: |
1196 | ret = -EINVAL; | 1225 | ret = -EINVAL; |