Skip to content

Commit 3673fb0

Browse files
osandovtorvalds
authored andcommitted
proc/kcore: hold lock during read
Now that we're using an rwsem, we can hold it during the entirety of read_kcore() and have a common return path. This is preparation for the next change. [[email protected]: fix locking bug reported by Tetsuo Handa] Link: http://lkml.kernel.org/r/d7cfbc1e8a76616f3b699eaff9df0a2730380534.1531953780.git.osandov@fb.com Signed-off-by: Omar Sandoval <[email protected]> Cc: Alexey Dobriyan <[email protected]> Cc: Bhupesh Sharma <[email protected]> Cc: Eric Biederman <[email protected]> Cc: James Morse <[email protected]> Cc: Tetsuo Handa <[email protected]> Cc: Stephen Rothwell <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent b66fb00 commit 3673fb0

File tree

1 file changed

+40
-30
lines changed

1 file changed

+40
-30
lines changed

fs/proc/kcore.c

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -440,19 +440,18 @@ static ssize_t
440440
read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
441441
{
442442
char *buf = file->private_data;
443-
ssize_t acc = 0;
444443
size_t size, tsz;
445444
size_t elf_buflen;
446445
int nphdr;
447446
unsigned long start;
447+
size_t orig_buflen = buflen;
448+
int ret = 0;
448449

449450
down_read(&kclist_lock);
450451
size = get_kcore_size(&nphdr, &elf_buflen);
451452

452-
if (buflen == 0 || *fpos >= size) {
453-
up_read(&kclist_lock);
454-
return 0;
455-
}
453+
if (buflen == 0 || *fpos >= size)
454+
goto out;
456455

457456
/* trim buflen to not go beyond EOF */
458457
if (buflen > size - *fpos)
@@ -465,28 +464,26 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
465464
tsz = elf_buflen - *fpos;
466465
if (buflen < tsz)
467466
tsz = buflen;
468-
elf_buf = kzalloc(elf_buflen, GFP_ATOMIC);
467+
elf_buf = kzalloc(elf_buflen, GFP_KERNEL);
469468
if (!elf_buf) {
470-
up_read(&kclist_lock);
471-
return -ENOMEM;
469+
ret = -ENOMEM;
470+
goto out;
472471
}
473472
elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
474-
up_read(&kclist_lock);
475473
if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
476474
kfree(elf_buf);
477-
return -EFAULT;
475+
ret = -EFAULT;
476+
goto out;
478477
}
479478
kfree(elf_buf);
480479
buflen -= tsz;
481480
*fpos += tsz;
482481
buffer += tsz;
483-
acc += tsz;
484482

485483
/* leave now if filled buffer already */
486484
if (buflen == 0)
487-
return acc;
488-
} else
489-
up_read(&kclist_lock);
485+
goto out;
486+
}
490487

491488
/*
492489
* Check to see if our file offset matches with any of
@@ -499,52 +496,65 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
499496
while (buflen) {
500497
struct kcore_list *m;
501498

502-
down_read(&kclist_lock);
503499
list_for_each_entry(m, &kclist_head, list) {
504500
if (start >= m->addr && start < (m->addr+m->size))
505501
break;
506502
}
507-
up_read(&kclist_lock);
508503

509504
if (&m->list == &kclist_head) {
510-
if (clear_user(buffer, tsz))
511-
return -EFAULT;
505+
if (clear_user(buffer, tsz)) {
506+
ret = -EFAULT;
507+
goto out;
508+
}
512509
} else if (m->type == KCORE_VMALLOC) {
513510
vread(buf, (char *)start, tsz);
514511
/* we have to zero-fill user buffer even if no read */
515-
if (copy_to_user(buffer, buf, tsz))
516-
return -EFAULT;
512+
if (copy_to_user(buffer, buf, tsz)) {
513+
ret = -EFAULT;
514+
goto out;
515+
}
517516
} else if (m->type == KCORE_USER) {
518517
/* User page is handled prior to normal kernel page: */
519-
if (copy_to_user(buffer, (char *)start, tsz))
520-
return -EFAULT;
518+
if (copy_to_user(buffer, (char *)start, tsz)) {
519+
ret = -EFAULT;
520+
goto out;
521+
}
521522
} else {
522523
if (kern_addr_valid(start)) {
523524
/*
524525
* Using bounce buffer to bypass the
525526
* hardened user copy kernel text checks.
526527
*/
527528
if (probe_kernel_read(buf, (void *) start, tsz)) {
528-
if (clear_user(buffer, tsz))
529-
return -EFAULT;
529+
if (clear_user(buffer, tsz)) {
530+
ret = -EFAULT;
531+
goto out;
532+
}
530533
} else {
531-
if (copy_to_user(buffer, buf, tsz))
532-
return -EFAULT;
534+
if (copy_to_user(buffer, buf, tsz)) {
535+
ret = -EFAULT;
536+
goto out;
537+
}
533538
}
534539
} else {
535-
if (clear_user(buffer, tsz))
536-
return -EFAULT;
540+
if (clear_user(buffer, tsz)) {
541+
ret = -EFAULT;
542+
goto out;
543+
}
537544
}
538545
}
539546
buflen -= tsz;
540547
*fpos += tsz;
541548
buffer += tsz;
542-
acc += tsz;
543549
start += tsz;
544550
tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
545551
}
546552

547-
return acc;
553+
out:
554+
up_read(&kclist_lock);
555+
if (ret)
556+
return ret;
557+
return orig_buflen - buflen;
548558
}
549559

550560

0 commit comments

Comments
 (0)