@@ -157,17 +157,18 @@ static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
157
157
}
158
158
buf -> result ++ ;
159
159
dirent = buf -> dirent ;
160
- if (!access_ok (dirent ,
160
+ if (!user_write_access_begin (dirent ,
161
161
(unsigned long )(dirent -> d_name + namlen + 1 ) -
162
162
(unsigned long )dirent ))
163
163
goto efault ;
164
- if ( __put_user (d_ino , & dirent -> d_ino ) ||
165
- __put_user (offset , & dirent -> d_offset ) ||
166
- __put_user (namlen , & dirent -> d_namlen ) ||
167
- __copy_to_user (dirent -> d_name , name , namlen ) ||
168
- __put_user (0 , dirent -> d_name + namlen ))
169
- goto efault ;
164
+ unsafe_put_user (d_ino , & dirent -> d_ino , efault_end );
165
+ unsafe_put_user (offset , & dirent -> d_offset , efault_end );
166
+ unsafe_put_user (namlen , & dirent -> d_namlen , efault_end );
167
+ unsafe_copy_dirent_name (dirent -> d_name , name , namlen , efault_end );
168
+ user_write_access_end ();
170
169
return 0 ;
170
+ efault_end :
171
+ user_write_access_end ();
171
172
efault :
172
173
buf -> result = - EFAULT ;
173
174
return - EFAULT ;
@@ -242,7 +243,7 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
242
243
return - EINTR ;
243
244
dirent = buf -> current_dir ;
244
245
prev = (void __user * ) dirent - prev_reclen ;
245
- if (!user_access_begin (prev , reclen + prev_reclen ))
246
+ if (!user_write_access_begin (prev , reclen + prev_reclen ))
246
247
goto efault ;
247
248
248
249
/* This might be 'dirent->d_off', but if so it will get overwritten */
@@ -251,14 +252,14 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
251
252
unsafe_put_user (reclen , & dirent -> d_reclen , efault_end );
252
253
unsafe_put_user (d_type , (char __user * ) dirent + reclen - 1 , efault_end );
253
254
unsafe_copy_dirent_name (dirent -> d_name , name , namlen , efault_end );
254
- user_access_end ();
255
+ user_write_access_end ();
255
256
256
257
buf -> current_dir = (void __user * )dirent + reclen ;
257
258
buf -> prev_reclen = reclen ;
258
259
buf -> count -= reclen ;
259
260
return 0 ;
260
261
efault_end :
261
- user_access_end ();
262
+ user_write_access_end ();
262
263
efault :
263
264
buf -> error = - EFAULT ;
264
265
return - EFAULT ;
@@ -275,9 +276,6 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
275
276
};
276
277
int error ;
277
278
278
- if (!access_ok (dirent , count ))
279
- return - EFAULT ;
280
-
281
279
f = fdget_pos (fd );
282
280
if (!f .file )
283
281
return - EBADF ;
@@ -327,7 +325,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
327
325
return - EINTR ;
328
326
dirent = buf -> current_dir ;
329
327
prev = (void __user * )dirent - prev_reclen ;
330
- if (!user_access_begin (prev , reclen + prev_reclen ))
328
+ if (!user_write_access_begin (prev , reclen + prev_reclen ))
331
329
goto efault ;
332
330
333
331
/* This might be 'dirent->d_off', but if so it will get overwritten */
@@ -336,15 +334,15 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
336
334
unsafe_put_user (reclen , & dirent -> d_reclen , efault_end );
337
335
unsafe_put_user (d_type , & dirent -> d_type , efault_end );
338
336
unsafe_copy_dirent_name (dirent -> d_name , name , namlen , efault_end );
339
- user_access_end ();
337
+ user_write_access_end ();
340
338
341
339
buf -> prev_reclen = reclen ;
342
340
buf -> current_dir = (void __user * )dirent + reclen ;
343
341
buf -> count -= reclen ;
344
342
return 0 ;
345
343
346
344
efault_end :
347
- user_access_end ();
345
+ user_write_access_end ();
348
346
efault :
349
347
buf -> error = - EFAULT ;
350
348
return - EFAULT ;
@@ -361,9 +359,6 @@ int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
361
359
};
362
360
int error ;
363
361
364
- if (!access_ok (dirent , count ))
365
- return - EFAULT ;
366
-
367
362
f = fdget_pos (fd );
368
363
if (!f .file )
369
364
return - EBADF ;
@@ -376,7 +371,7 @@ int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
376
371
typeof (lastdirent -> d_off ) d_off = buf .ctx .pos ;
377
372
378
373
lastdirent = (void __user * ) buf .current_dir - buf .prev_reclen ;
379
- if (__put_user (d_off , & lastdirent -> d_off ))
374
+ if (put_user (d_off , & lastdirent -> d_off ))
380
375
error = - EFAULT ;
381
376
else
382
377
error = count - buf .count ;
@@ -424,17 +419,18 @@ static int compat_fillonedir(struct dir_context *ctx, const char *name,
424
419
}
425
420
buf -> result ++ ;
426
421
dirent = buf -> dirent ;
427
- if (!access_ok (dirent ,
422
+ if (!user_write_access_begin (dirent ,
428
423
(unsigned long )(dirent -> d_name + namlen + 1 ) -
429
424
(unsigned long )dirent ))
430
425
goto efault ;
431
- if ( __put_user (d_ino , & dirent -> d_ino ) ||
432
- __put_user (offset , & dirent -> d_offset ) ||
433
- __put_user (namlen , & dirent -> d_namlen ) ||
434
- __copy_to_user (dirent -> d_name , name , namlen ) ||
435
- __put_user (0 , dirent -> d_name + namlen ))
436
- goto efault ;
426
+ unsafe_put_user (d_ino , & dirent -> d_ino , efault_end );
427
+ unsafe_put_user (offset , & dirent -> d_offset , efault_end );
428
+ unsafe_put_user (namlen , & dirent -> d_namlen , efault_end );
429
+ unsafe_copy_dirent_name (dirent -> d_name , name , namlen , efault_end );
430
+ user_write_access_end ();
437
431
return 0 ;
432
+ efault_end :
433
+ user_write_access_end ();
438
434
efault :
439
435
buf -> result = - EFAULT ;
440
436
return - EFAULT ;
@@ -471,21 +467,25 @@ struct compat_linux_dirent {
471
467
struct compat_getdents_callback {
472
468
struct dir_context ctx ;
473
469
struct compat_linux_dirent __user * current_dir ;
474
- struct compat_linux_dirent __user * previous ;
470
+ int prev_reclen ;
475
471
int count ;
476
472
int error ;
477
473
};
478
474
479
475
static int compat_filldir (struct dir_context * ctx , const char * name , int namlen ,
480
476
loff_t offset , u64 ino , unsigned int d_type )
481
477
{
482
- struct compat_linux_dirent __user * dirent ;
478
+ struct compat_linux_dirent __user * dirent , * prev ;
483
479
struct compat_getdents_callback * buf =
484
480
container_of (ctx , struct compat_getdents_callback , ctx );
485
481
compat_ulong_t d_ino ;
486
482
int reclen = ALIGN (offsetof(struct compat_linux_dirent , d_name ) +
487
483
namlen + 2 , sizeof (compat_long_t ));
484
+ int prev_reclen ;
488
485
486
+ buf -> error = verify_dirent_name (name , namlen );
487
+ if (unlikely (buf -> error ))
488
+ return buf -> error ;
489
489
buf -> error = - EINVAL ; /* only used if we fail.. */
490
490
if (reclen > buf -> count )
491
491
return - EINVAL ;
@@ -494,29 +494,27 @@ static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
494
494
buf -> error = - EOVERFLOW ;
495
495
return - EOVERFLOW ;
496
496
}
497
- dirent = buf -> previous ;
498
- if (dirent ) {
499
- if (signal_pending (current ))
500
- return - EINTR ;
501
- if (__put_user (offset , & dirent -> d_off ))
502
- goto efault ;
503
- }
497
+ prev_reclen = buf -> prev_reclen ;
498
+ if (prev_reclen && signal_pending (current ))
499
+ return - EINTR ;
504
500
dirent = buf -> current_dir ;
505
- if (__put_user (d_ino , & dirent -> d_ino ))
506
- goto efault ;
507
- if (__put_user (reclen , & dirent -> d_reclen ))
508
- goto efault ;
509
- if (copy_to_user (dirent -> d_name , name , namlen ))
510
- goto efault ;
511
- if (__put_user (0 , dirent -> d_name + namlen ))
512
- goto efault ;
513
- if (__put_user (d_type , (char __user * ) dirent + reclen - 1 ))
501
+ prev = (void __user * ) dirent - prev_reclen ;
502
+ if (!user_write_access_begin (prev , reclen + prev_reclen ))
514
503
goto efault ;
515
- buf -> previous = dirent ;
516
- dirent = (void __user * )dirent + reclen ;
517
- buf -> current_dir = dirent ;
504
+
505
+ unsafe_put_user (offset , & prev -> d_off , efault_end );
506
+ unsafe_put_user (d_ino , & dirent -> d_ino , efault_end );
507
+ unsafe_put_user (reclen , & dirent -> d_reclen , efault_end );
508
+ unsafe_put_user (d_type , (char __user * ) dirent + reclen - 1 , efault_end );
509
+ unsafe_copy_dirent_name (dirent -> d_name , name , namlen , efault_end );
510
+ user_write_access_end ();
511
+
512
+ buf -> prev_reclen = reclen ;
513
+ buf -> current_dir = (void __user * )dirent + reclen ;
518
514
buf -> count -= reclen ;
519
515
return 0 ;
516
+ efault_end :
517
+ user_write_access_end ();
520
518
efault :
521
519
buf -> error = - EFAULT ;
522
520
return - EFAULT ;
@@ -526,26 +524,24 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
526
524
struct compat_linux_dirent __user * , dirent , unsigned int , count )
527
525
{
528
526
struct fd f ;
529
- struct compat_linux_dirent __user * lastdirent ;
530
527
struct compat_getdents_callback buf = {
531
528
.ctx .actor = compat_filldir ,
532
529
.current_dir = dirent ,
533
530
.count = count
534
531
};
535
532
int error ;
536
533
537
- if (!access_ok (dirent , count ))
538
- return - EFAULT ;
539
-
540
534
f = fdget_pos (fd );
541
535
if (!f .file )
542
536
return - EBADF ;
543
537
544
538
error = iterate_dir (f .file , & buf .ctx );
545
539
if (error >= 0 )
546
540
error = buf .error ;
547
- lastdirent = buf .previous ;
548
- if (lastdirent ) {
541
+ if (buf .prev_reclen ) {
542
+ struct compat_linux_dirent __user * lastdirent ;
543
+ lastdirent = (void __user * )buf .current_dir - buf .prev_reclen ;
544
+
549
545
if (put_user (buf .ctx .pos , & lastdirent -> d_off ))
550
546
error = - EFAULT ;
551
547
else
0 commit comments