Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'cleanup-kernel_read_write' of git://git.infradead.org/users/hch/misc

Pull in-kernel read and write op cleanups from Christoph Hellwig:
"Cleanup in-kernel read and write operations

Reshuffle the (__)kernel_read and (__)kernel_write helpers, and ensure
all users of in-kernel file I/O use them if they don't use iov_iter
based methods already.

The new WARN_ONs in combination with syzcaller already found a missing
input validation in 9p. The fix should be on your way through the
maintainer ASAP".

[ This is prep-work for the real changes coming 5.9 ]

* tag 'cleanup-kernel_read_write' of git://git.infradead.org/users/hch/misc:
fs: remove __vfs_read
fs: implement kernel_read using __kernel_read
integrity/ima: switch to using __kernel_read
fs: add a __kernel_read helper
fs: remove __vfs_write
fs: implement kernel_write using __kernel_write
fs: check FMODE_WRITE in __kernel_write
fs: unexport __kernel_write
bpfilter: switch to kernel_write
autofs: switch to kernel_write
cachefiles: switch to kernel_write

+82 -75
+1 -1
fs/autofs/waitq.c
··· 53 53 54 54 mutex_lock(&sbi->pipe_mutex); 55 55 while (bytes) { 56 - wr = __kernel_write(file, data, bytes, &file->f_pos); 56 + wr = kernel_write(file, data, bytes, &file->f_pos); 57 57 if (wr <= 0) 58 58 break; 59 59 data += wr;
+1 -1
fs/cachefiles/rdwr.c
··· 937 937 } 938 938 939 939 data = kmap(page); 940 - ret = __kernel_write(file, data, len, &pos); 940 + ret = kernel_write(file, data, len, &pos); 941 941 kunmap(page); 942 942 fput(file); 943 943 if (ret != len)
+77 -58
fs/read_write.c
··· 419 419 return ret; 420 420 } 421 421 422 - ssize_t __vfs_read(struct file *file, char __user *buf, size_t count, 423 - loff_t *pos) 422 + ssize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) 424 423 { 425 - if (file->f_op->read) 426 - return file->f_op->read(file, buf, count, pos); 427 - else if (file->f_op->read_iter) 428 - return new_sync_read(file, buf, count, pos); 429 - else 424 + mm_segment_t old_fs = get_fs(); 425 + ssize_t ret; 426 + 427 + if (WARN_ON_ONCE(!(file->f_mode & FMODE_READ))) 430 428 return -EINVAL; 429 + if (!(file->f_mode & FMODE_CAN_READ)) 430 + return -EINVAL; 431 + 432 + if (count > MAX_RW_COUNT) 433 + count = MAX_RW_COUNT; 434 + set_fs(KERNEL_DS); 435 + if (file->f_op->read) 436 + ret = file->f_op->read(file, (void __user *)buf, count, pos); 437 + else if (file->f_op->read_iter) 438 + ret = new_sync_read(file, (void __user *)buf, count, pos); 439 + else 440 + ret = -EINVAL; 441 + set_fs(old_fs); 442 + if (ret > 0) { 443 + fsnotify_access(file); 444 + add_rchar(current, ret); 445 + } 446 + inc_syscr(current); 447 + return ret; 431 448 } 432 449 433 450 ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) 434 451 { 435 - mm_segment_t old_fs; 436 - ssize_t result; 452 + ssize_t ret; 437 453 438 - old_fs = get_fs(); 439 - set_fs(KERNEL_DS); 440 - /* The cast to a user pointer is valid due to the set_fs() */ 441 - result = vfs_read(file, (void __user *)buf, count, pos); 442 - set_fs(old_fs); 443 - return result; 454 + ret = rw_verify_area(READ, file, pos, count); 455 + if (ret) 456 + return ret; 457 + return __kernel_read(file, buf, count, pos); 444 458 } 445 459 EXPORT_SYMBOL(kernel_read); 446 460 ··· 470 456 return -EFAULT; 471 457 472 458 ret = rw_verify_area(READ, file, pos, count); 473 - if (!ret) { 474 - if (count > MAX_RW_COUNT) 475 - count = MAX_RW_COUNT; 476 - ret = __vfs_read(file, buf, count, pos); 477 - if (ret > 0) { 478 - fsnotify_access(file); 479 - add_rchar(current, ret); 480 - } 481 - inc_syscr(current); 482 - } 459 + if (ret) 460 + return ret; 461 + if (count > MAX_RW_COUNT) 462 + count = MAX_RW_COUNT; 483 463 464 + if (file->f_op->read) 465 + ret = file->f_op->read(file, buf, count, pos); 466 + else if (file->f_op->read_iter) 467 + ret = new_sync_read(file, buf, count, pos); 468 + else 469 + ret = -EINVAL; 470 + if (ret > 0) { 471 + fsnotify_access(file); 472 + add_rchar(current, ret); 473 + } 474 + inc_syscr(current); 484 475 return ret; 485 476 } 486 477 ··· 507 488 return ret; 508 489 } 509 490 510 - static ssize_t __vfs_write(struct file *file, const char __user *p, 511 - size_t count, loff_t *pos) 512 - { 513 - if (file->f_op->write) 514 - return file->f_op->write(file, p, count, pos); 515 - else if (file->f_op->write_iter) 516 - return new_sync_write(file, p, count, pos); 517 - else 518 - return -EINVAL; 519 - } 520 - 491 + /* caller is responsible for file_start_write/file_end_write */ 521 492 ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) 522 493 { 523 494 mm_segment_t old_fs; 524 495 const char __user *p; 525 496 ssize_t ret; 526 497 498 + if (WARN_ON_ONCE(!(file->f_mode & FMODE_WRITE))) 499 + return -EBADF; 527 500 if (!(file->f_mode & FMODE_CAN_WRITE)) 528 501 return -EINVAL; 529 502 ··· 524 513 p = (__force const char __user *)buf; 525 514 if (count > MAX_RW_COUNT) 526 515 count = MAX_RW_COUNT; 527 - ret = __vfs_write(file, p, count, pos); 516 + if (file->f_op->write) 517 + ret = file->f_op->write(file, p, count, pos); 518 + else if (file->f_op->write_iter) 519 + ret = new_sync_write(file, p, count, pos); 520 + else 521 + ret = -EINVAL; 528 522 set_fs(old_fs); 529 523 if (ret > 0) { 530 524 fsnotify_modify(file); ··· 538 522 inc_syscw(current); 539 523 return ret; 540 524 } 541 - EXPORT_SYMBOL(__kernel_write); 542 525 543 526 ssize_t kernel_write(struct file *file, const void *buf, size_t count, 544 527 loff_t *pos) 545 528 { 546 - mm_segment_t old_fs; 547 - ssize_t res; 529 + ssize_t ret; 548 530 549 - old_fs = get_fs(); 550 - set_fs(KERNEL_DS); 551 - /* The cast to a user pointer is valid due to the set_fs() */ 552 - res = vfs_write(file, (__force const char __user *)buf, count, pos); 553 - set_fs(old_fs); 531 + ret = rw_verify_area(WRITE, file, pos, count); 532 + if (ret) 533 + return ret; 554 534 555 - return res; 535 + file_start_write(file); 536 + ret = __kernel_write(file, buf, count, pos); 537 + file_end_write(file); 538 + return ret; 556 539 } 557 540 EXPORT_SYMBOL(kernel_write); 558 541 ··· 567 552 return -EFAULT; 568 553 569 554 ret = rw_verify_area(WRITE, file, pos, count); 570 - if (!ret) { 571 - if (count > MAX_RW_COUNT) 572 - count = MAX_RW_COUNT; 573 - file_start_write(file); 574 - ret = __vfs_write(file, buf, count, pos); 575 - if (ret > 0) { 576 - fsnotify_modify(file); 577 - add_wchar(current, ret); 578 - } 579 - inc_syscw(current); 580 - file_end_write(file); 555 + if (ret) 556 + return ret; 557 + if (count > MAX_RW_COUNT) 558 + count = MAX_RW_COUNT; 559 + file_start_write(file); 560 + if (file->f_op->write) 561 + ret = file->f_op->write(file, buf, count, pos); 562 + else if (file->f_op->write_iter) 563 + ret = new_sync_write(file, buf, count, pos); 564 + else 565 + ret = -EINVAL; 566 + if (ret > 0) { 567 + fsnotify_modify(file); 568 + add_wchar(current, ret); 581 569 } 582 - 570 + inc_syscw(current); 571 + file_end_write(file); 583 572 return ret; 584 573 } 585 574
+1 -1
include/linux/fs.h
··· 1918 1918 struct iovec *fast_pointer, 1919 1919 struct iovec **ret_pointer); 1920 1920 1921 - extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *); 1922 1921 extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); 1923 1922 extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *); 1924 1923 extern ssize_t vfs_readv(struct file *, const struct iovec __user *, ··· 3033 3034 extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t, 3034 3035 enum kernel_read_file_id); 3035 3036 extern ssize_t kernel_read(struct file *, void *, size_t, loff_t *); 3037 + ssize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos); 3036 3038 extern ssize_t kernel_write(struct file *, const void *, size_t, loff_t *); 3037 3039 extern ssize_t __kernel_write(struct file *, const void *, size_t, loff_t *); 3038 3040 extern struct file * open_exec(const char *);
+1 -1
net/bpfilter/bpfilter_kern.c
··· 50 50 req.len = optlen; 51 51 if (!bpfilter_ops.info.pid) 52 52 goto out; 53 - n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req), 53 + n = kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req), 54 54 &pos); 55 55 if (n != sizeof(req)) { 56 56 pr_err("write fail %zd\n", n);
+1 -13
security/integrity/iint.c
··· 188 188 int integrity_kernel_read(struct file *file, loff_t offset, 189 189 void *addr, unsigned long count) 190 190 { 191 - mm_segment_t old_fs; 192 - char __user *buf = (char __user *)addr; 193 - ssize_t ret; 194 - 195 - if (!(file->f_mode & FMODE_READ)) 196 - return -EBADF; 197 - 198 - old_fs = get_fs(); 199 - set_fs(KERNEL_DS); 200 - ret = __vfs_read(file, buf, count, &offset); 201 - set_fs(old_fs); 202 - 203 - return ret; 191 + return __kernel_read(file, addr, count, &offset); 204 192 } 205 193 206 194 /*