@@ -205,43 +205,16 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
205
205
return result ;
206
206
}
207
207
208
- static ssize_t proc_pid_cmdline_read (struct file * file , char __user * buf ,
209
- size_t _count , loff_t * pos )
208
+ static ssize_t get_mm_cmdline (struct mm_struct * mm , char __user * buf ,
209
+ size_t count , loff_t * ppos )
210
210
{
211
- struct task_struct * tsk ;
212
- struct mm_struct * mm ;
213
- char * page ;
214
- unsigned long count = _count ;
215
211
unsigned long arg_start , arg_end , env_start , env_end ;
216
- unsigned long len1 , len2 ;
217
- char __user * buf0 = buf ;
218
- struct {
219
- unsigned long p ;
220
- unsigned long len ;
221
- } cmdline [2 ];
222
- char c ;
223
- int rv ;
224
-
225
- BUG_ON (* pos < 0 );
212
+ unsigned long pos , len ;
213
+ char * page ;
226
214
227
- tsk = get_proc_task (file_inode (file ));
228
- if (!tsk )
229
- return - ESRCH ;
230
- mm = get_task_mm (tsk );
231
- put_task_struct (tsk );
232
- if (!mm )
233
- return 0 ;
234
215
/* Check if process spawned far enough to have cmdline. */
235
- if (!mm -> env_end ) {
236
- rv = 0 ;
237
- goto out_mmput ;
238
- }
239
-
240
- page = (char * )__get_free_page (GFP_KERNEL );
241
- if (!page ) {
242
- rv = - ENOMEM ;
243
- goto out_mmput ;
244
- }
216
+ if (!mm -> env_end )
217
+ return 0 ;
245
218
246
219
spin_lock (& mm -> arg_lock );
247
220
arg_start = mm -> arg_start ;
@@ -250,97 +223,111 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
250
223
env_end = mm -> env_end ;
251
224
spin_unlock (& mm -> arg_lock );
252
225
253
- BUG_ON (arg_start > arg_end );
254
- BUG_ON (env_start > env_end );
255
-
256
- len1 = arg_end - arg_start ;
257
- len2 = env_end - env_start ;
258
-
259
- /* Empty ARGV. */
260
- if (len1 == 0 )
261
- goto end ;
226
+ if (arg_start >= arg_end )
227
+ return 0 ;
262
228
263
229
/*
264
- * Inherently racy -- command line shares address space
265
- * with code and data.
230
+ * We have traditionally allowed the user to re-write
231
+ * the argument strings and overflow the end result
232
+ * into the environment section. But only do that if
233
+ * the environment area is contiguous to the arguments.
266
234
*/
267
- if (access_remote_vm (mm , arg_end - 1 , & c , 1 , FOLL_ANON ) != 1 )
268
- goto end ;
269
-
270
- cmdline [0 ].p = arg_start ;
271
- cmdline [0 ].len = len1 ;
272
- if (c == '\0' ) {
273
- /* Command line (set of strings) occupies whole ARGV. */
274
- cmdline [1 ].len = 0 ;
275
- } else {
276
- /*
277
- * Command line (1 string) occupies ARGV and
278
- * extends into ENVP.
279
- */
280
- cmdline [1 ].p = env_start ;
281
- cmdline [1 ].len = len2 ;
282
- }
235
+ if (env_start != arg_end || env_start >= env_end )
236
+ env_start = env_end = arg_end ;
283
237
284
- {
285
- loff_t pos1 = * pos ;
286
- unsigned int i ;
238
+ /* We're not going to care if "*ppos" has high bits set */
239
+ pos = arg_start + * ppos ;
240
+
241
+ /* .. but we do check the result is in the proper range */
242
+ if (pos < arg_start || pos >= env_end )
243
+ return 0 ;
287
244
288
- i = 0 ;
289
- while (i < 2 && pos1 >= cmdline [i ].len ) {
290
- pos1 -= cmdline [i ].len ;
291
- i ++ ;
245
+ /* .. and we never go past env_end */
246
+ if (env_end - pos < count )
247
+ count = env_end - pos ;
248
+
249
+ page = (char * )__get_free_page (GFP_KERNEL );
250
+ if (!page )
251
+ return - ENOMEM ;
252
+
253
+ len = 0 ;
254
+ while (count ) {
255
+ int got ;
256
+ size_t size = min_t (size_t , PAGE_SIZE , count );
257
+
258
+ got = access_remote_vm (mm , pos , page , size , FOLL_ANON );
259
+ if (got <= 0 )
260
+ break ;
261
+
262
+ /* Don't walk past a NUL character once you hit arg_end */
263
+ if (pos + got >= arg_end ) {
264
+ int n = 0 ;
265
+
266
+ /*
267
+ * If we started before 'arg_end' but ended up
268
+ * at or after it, we start the NUL character
269
+ * check at arg_end-1 (where we expect the normal
270
+ * EOF to be).
271
+ *
272
+ * NOTE! This is smaller than 'got', because
273
+ * pos + got >= arg_end
274
+ */
275
+ if (pos < arg_end )
276
+ n = arg_end - pos - 1 ;
277
+
278
+ /* Cut off at first NUL after 'n' */
279
+ got = n + strnlen (page + n , got - n );
280
+ if (!got )
281
+ break ;
292
282
}
293
- while (i < 2 ) {
294
- unsigned long p ;
295
- unsigned long len ;
296
-
297
- p = cmdline [i ].p + pos1 ;
298
- len = cmdline [i ].len - pos1 ;
299
- while (count > 0 && len > 0 ) {
300
- unsigned int nr_read , nr_write ;
301
-
302
- nr_read = min3 (count , len , PAGE_SIZE );
303
- nr_read = access_remote_vm (mm , p , page , nr_read , FOLL_ANON );
304
- if (nr_read == 0 )
305
- goto end ;
306
-
307
- /*
308
- * Command line can be shorter than whole ARGV
309
- * even if last "marker" byte says it is not.
310
- */
311
- if (c == '\0' )
312
- nr_write = nr_read ;
313
- else
314
- nr_write = strnlen (page , nr_read );
315
-
316
- if (copy_to_user (buf , page , nr_write )) {
317
- rv = - EFAULT ;
318
- goto out_free_page ;
319
- }
320
-
321
- p += nr_write ;
322
- len -= nr_write ;
323
- buf += nr_write ;
324
- count -= nr_write ;
325
-
326
- if (nr_write < nr_read )
327
- goto end ;
328
- }
329
283
330
- /* Only first chunk can be read partially. */
331
- pos1 = 0 ;
332
- i ++ ;
284
+ got -= copy_to_user (buf , page , got );
285
+ if (unlikely (!got )) {
286
+ if (!len )
287
+ len = - EFAULT ;
288
+ break ;
333
289
}
290
+ pos += got ;
291
+ buf += got ;
292
+ len += got ;
293
+ count -= got ;
334
294
}
335
295
336
- end :
337
- * pos += buf - buf0 ;
338
- rv = buf - buf0 ;
339
- out_free_page :
340
296
free_page ((unsigned long )page );
341
- out_mmput :
297
+ return len ;
298
+ }
299
+
300
+ static ssize_t get_task_cmdline (struct task_struct * tsk , char __user * buf ,
301
+ size_t count , loff_t * pos )
302
+ {
303
+ struct mm_struct * mm ;
304
+ ssize_t ret ;
305
+
306
+ mm = get_task_mm (tsk );
307
+ if (!mm )
308
+ return 0 ;
309
+
310
+ ret = get_mm_cmdline (mm , buf , count , pos );
342
311
mmput (mm );
343
- return rv ;
312
+ return ret ;
313
+ }
314
+
315
+ static ssize_t proc_pid_cmdline_read (struct file * file , char __user * buf ,
316
+ size_t count , loff_t * pos )
317
+ {
318
+ struct task_struct * tsk ;
319
+ ssize_t ret ;
320
+
321
+ BUG_ON (* pos < 0 );
322
+
323
+ tsk = get_proc_task (file_inode (file ));
324
+ if (!tsk )
325
+ return - ESRCH ;
326
+ ret = get_task_cmdline (tsk , buf , count , pos );
327
+ put_task_struct (tsk );
328
+ if (ret > 0 )
329
+ * pos += ret ;
330
+ return ret ;
344
331
}
345
332
346
333
static const struct file_operations proc_pid_cmdline_ops = {
0 commit comments