Skip to content

Commit e148a8f

Browse files
committed
Merge branch 'uaccess.readdir' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull uaccess/readdir updates from Al Viro: "Finishing the conversion of readdir.c to unsafe_... API. This includes the uaccess_{read,write}_begin series by Christophe Leroy" * 'uaccess.readdir' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: readdir.c: get rid of the last __put_user(), drop now-useless access_ok() readdir.c: get compat_filldir() more or less in sync with filldir() switch readdir(2) to unsafe_copy_dirent_name() drm/i915/gem: Replace user_access_begin by user_write_access_begin uaccess: Selectively open read or write user access uaccess: Add user_read_access_begin/end and user_write_access_begin/end
2 parents e0cd920 + 5fb1514 commit e148a8f

File tree

8 files changed

+80
-75
lines changed

8 files changed

+80
-75
lines changed

drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,7 +2794,8 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
27942794
* And this range already got effectively checked earlier
27952795
* when we did the "copy_from_user()" above.
27962796
*/
2797-
if (!user_access_begin(user_exec_list, count * sizeof(*user_exec_list)))
2797+
if (!user_write_access_begin(user_exec_list,
2798+
count * sizeof(*user_exec_list)))
27982799
goto end;
27992800

28002801
for (i = 0; i < args->buffer_count; i++) {
@@ -2808,7 +2809,7 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
28082809
end_user);
28092810
}
28102811
end_user:
2811-
user_access_end();
2812+
user_write_access_end();
28122813
end:;
28132814
}
28142815

fs/readdir.c

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -157,17 +157,18 @@ static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
157157
}
158158
buf->result++;
159159
dirent = buf->dirent;
160-
if (!access_ok(dirent,
160+
if (!user_write_access_begin(dirent,
161161
(unsigned long)(dirent->d_name + namlen + 1) -
162162
(unsigned long)dirent))
163163
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();
170169
return 0;
170+
efault_end:
171+
user_write_access_end();
171172
efault:
172173
buf->result = -EFAULT;
173174
return -EFAULT;
@@ -242,7 +243,7 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
242243
return -EINTR;
243244
dirent = buf->current_dir;
244245
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))
246247
goto efault;
247248

248249
/* 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,
251252
unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
252253
unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
253254
unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
254-
user_access_end();
255+
user_write_access_end();
255256

256257
buf->current_dir = (void __user *)dirent + reclen;
257258
buf->prev_reclen = reclen;
258259
buf->count -= reclen;
259260
return 0;
260261
efault_end:
261-
user_access_end();
262+
user_write_access_end();
262263
efault:
263264
buf->error = -EFAULT;
264265
return -EFAULT;
@@ -275,9 +276,6 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
275276
};
276277
int error;
277278

278-
if (!access_ok(dirent, count))
279-
return -EFAULT;
280-
281279
f = fdget_pos(fd);
282280
if (!f.file)
283281
return -EBADF;
@@ -327,7 +325,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
327325
return -EINTR;
328326
dirent = buf->current_dir;
329327
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))
331329
goto efault;
332330

333331
/* 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,
336334
unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
337335
unsafe_put_user(d_type, &dirent->d_type, efault_end);
338336
unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
339-
user_access_end();
337+
user_write_access_end();
340338

341339
buf->prev_reclen = reclen;
342340
buf->current_dir = (void __user *)dirent + reclen;
343341
buf->count -= reclen;
344342
return 0;
345343

346344
efault_end:
347-
user_access_end();
345+
user_write_access_end();
348346
efault:
349347
buf->error = -EFAULT;
350348
return -EFAULT;
@@ -361,9 +359,6 @@ int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
361359
};
362360
int error;
363361

364-
if (!access_ok(dirent, count))
365-
return -EFAULT;
366-
367362
f = fdget_pos(fd);
368363
if (!f.file)
369364
return -EBADF;
@@ -376,7 +371,7 @@ int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
376371
typeof(lastdirent->d_off) d_off = buf.ctx.pos;
377372

378373
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))
380375
error = -EFAULT;
381376
else
382377
error = count - buf.count;
@@ -424,17 +419,18 @@ static int compat_fillonedir(struct dir_context *ctx, const char *name,
424419
}
425420
buf->result++;
426421
dirent = buf->dirent;
427-
if (!access_ok(dirent,
422+
if (!user_write_access_begin(dirent,
428423
(unsigned long)(dirent->d_name + namlen + 1) -
429424
(unsigned long)dirent))
430425
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();
437431
return 0;
432+
efault_end:
433+
user_write_access_end();
438434
efault:
439435
buf->result = -EFAULT;
440436
return -EFAULT;
@@ -471,21 +467,25 @@ struct compat_linux_dirent {
471467
struct compat_getdents_callback {
472468
struct dir_context ctx;
473469
struct compat_linux_dirent __user *current_dir;
474-
struct compat_linux_dirent __user *previous;
470+
int prev_reclen;
475471
int count;
476472
int error;
477473
};
478474

479475
static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
480476
loff_t offset, u64 ino, unsigned int d_type)
481477
{
482-
struct compat_linux_dirent __user * dirent;
478+
struct compat_linux_dirent __user *dirent, *prev;
483479
struct compat_getdents_callback *buf =
484480
container_of(ctx, struct compat_getdents_callback, ctx);
485481
compat_ulong_t d_ino;
486482
int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
487483
namlen + 2, sizeof(compat_long_t));
484+
int prev_reclen;
488485

486+
buf->error = verify_dirent_name(name, namlen);
487+
if (unlikely(buf->error))
488+
return buf->error;
489489
buf->error = -EINVAL; /* only used if we fail.. */
490490
if (reclen > buf->count)
491491
return -EINVAL;
@@ -494,29 +494,27 @@ static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
494494
buf->error = -EOVERFLOW;
495495
return -EOVERFLOW;
496496
}
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;
504500
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))
514503
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;
518514
buf->count -= reclen;
519515
return 0;
516+
efault_end:
517+
user_write_access_end();
520518
efault:
521519
buf->error = -EFAULT;
522520
return -EFAULT;
@@ -526,26 +524,24 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
526524
struct compat_linux_dirent __user *, dirent, unsigned int, count)
527525
{
528526
struct fd f;
529-
struct compat_linux_dirent __user * lastdirent;
530527
struct compat_getdents_callback buf = {
531528
.ctx.actor = compat_filldir,
532529
.current_dir = dirent,
533530
.count = count
534531
};
535532
int error;
536533

537-
if (!access_ok(dirent, count))
538-
return -EFAULT;
539-
540534
f = fdget_pos(fd);
541535
if (!f.file)
542536
return -EBADF;
543537

544538
error = iterate_dir(f.file, &buf.ctx);
545539
if (error >= 0)
546540
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+
549545
if (put_user(buf.ctx.pos, &lastdirent->d_off))
550546
error = -EFAULT;
551547
else

include/linux/uaccess.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,14 @@ extern long strnlen_unsafe_user(const void __user *unsafe_addr, long count);
378378
static inline unsigned long user_access_save(void) { return 0UL; }
379379
static inline void user_access_restore(unsigned long flags) { }
380380
#endif
381+
#ifndef user_write_access_begin
382+
#define user_write_access_begin user_access_begin
383+
#define user_write_access_end user_access_end
384+
#endif
385+
#ifndef user_read_access_begin
386+
#define user_read_access_begin user_access_begin
387+
#define user_read_access_end user_access_end
388+
#endif
381389

382390
#ifdef CONFIG_HARDENED_USERCOPY
383391
void usercopy_warn(const char *name, const char *detail, bool to_user,

kernel/compat.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
199199
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
200200
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
201201

202-
if (!user_access_begin(umask, bitmap_size / 8))
202+
if (!user_read_access_begin(umask, bitmap_size / 8))
203203
return -EFAULT;
204204

205205
while (nr_compat_longs > 1) {
@@ -211,11 +211,11 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
211211
}
212212
if (nr_compat_longs)
213213
unsafe_get_user(*mask, umask++, Efault);
214-
user_access_end();
214+
user_read_access_end();
215215
return 0;
216216

217217
Efault:
218-
user_access_end();
218+
user_read_access_end();
219219
return -EFAULT;
220220
}
221221

@@ -228,7 +228,7 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
228228
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
229229
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
230230

231-
if (!user_access_begin(umask, bitmap_size / 8))
231+
if (!user_write_access_begin(umask, bitmap_size / 8))
232232
return -EFAULT;
233233

234234
while (nr_compat_longs > 1) {
@@ -239,10 +239,10 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
239239
}
240240
if (nr_compat_longs)
241241
unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
242-
user_access_end();
242+
user_write_access_end();
243243
return 0;
244244
Efault:
245-
user_access_end();
245+
user_write_access_end();
246246
return -EFAULT;
247247
}
248248

kernel/exit.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
15581558
if (!infop)
15591559
return err;
15601560

1561-
if (!user_access_begin(infop, sizeof(*infop)))
1561+
if (!user_write_access_begin(infop, sizeof(*infop)))
15621562
return -EFAULT;
15631563

15641564
unsafe_put_user(signo, &infop->si_signo, Efault);
@@ -1567,10 +1567,10 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
15671567
unsafe_put_user(info.pid, &infop->si_pid, Efault);
15681568
unsafe_put_user(info.uid, &infop->si_uid, Efault);
15691569
unsafe_put_user(info.status, &infop->si_status, Efault);
1570-
user_access_end();
1570+
user_write_access_end();
15711571
return err;
15721572
Efault:
1573-
user_access_end();
1573+
user_write_access_end();
15741574
return -EFAULT;
15751575
}
15761576

@@ -1685,7 +1685,7 @@ COMPAT_SYSCALL_DEFINE5(waitid,
16851685
if (!infop)
16861686
return err;
16871687

1688-
if (!user_access_begin(infop, sizeof(*infop)))
1688+
if (!user_write_access_begin(infop, sizeof(*infop)))
16891689
return -EFAULT;
16901690

16911691
unsafe_put_user(signo, &infop->si_signo, Efault);
@@ -1694,10 +1694,10 @@ COMPAT_SYSCALL_DEFINE5(waitid,
16941694
unsafe_put_user(info.pid, &infop->si_pid, Efault);
16951695
unsafe_put_user(info.uid, &infop->si_uid, Efault);
16961696
unsafe_put_user(info.status, &infop->si_status, Efault);
1697-
user_access_end();
1697+
user_write_access_end();
16981698
return err;
16991699
Efault:
1700-
user_access_end();
1700+
user_write_access_end();
17011701
return -EFAULT;
17021702
}
17031703
#endif

lib/strncpy_from_user.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
116116

117117
kasan_check_write(dst, count);
118118
check_object_size(dst, count, false);
119-
if (user_access_begin(src, max)) {
119+
if (user_read_access_begin(src, max)) {
120120
retval = do_strncpy_from_user(dst, src, count, max);
121-
user_access_end();
121+
user_read_access_end();
122122
return retval;
123123
}
124124
}

lib/strnlen_user.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ long strnlen_user(const char __user *str, long count)
109109
if (max > count)
110110
max = count;
111111

112-
if (user_access_begin(str, max)) {
112+
if (user_read_access_begin(str, max)) {
113113
retval = do_strnlen_user(str, count, max);
114-
user_access_end();
114+
user_read_access_end();
115115
return retval;
116116
}
117117
}

0 commit comments

Comments
 (0)