| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 1 | 2 | /* | 
|---|
| 2 | 3 | *  linux/fs/open.c | 
|---|
| 3 | 4 | * | 
|---|
| .. | .. | 
|---|
| 33 | 34 | #include <linux/compat.h> | 
|---|
| 34 | 35 |  | 
|---|
| 35 | 36 | #include "internal.h" | 
|---|
|  | 37 | +#include <trace/hooks/syscall_check.h> | 
|---|
| 36 | 38 |  | 
|---|
| 37 |  | -int do_truncate2(struct vfsmount *mnt, struct dentry *dentry, loff_t length, | 
|---|
| 38 |  | -		unsigned int time_attrs, struct file *filp) | 
|---|
|  | 39 | +int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | 
|---|
|  | 40 | +	struct file *filp) | 
|---|
| 39 | 41 | { | 
|---|
| 40 | 42 | int ret; | 
|---|
| 41 | 43 | struct iattr newattrs; | 
|---|
| .. | .. | 
|---|
| 60 | 62 |  | 
|---|
| 61 | 63 | inode_lock(dentry->d_inode); | 
|---|
| 62 | 64 | /* Note any delegations or leases have already been broken: */ | 
|---|
| 63 |  | -	ret = notify_change2(mnt, dentry, &newattrs, NULL); | 
|---|
|  | 65 | +	ret = notify_change(dentry, &newattrs, NULL); | 
|---|
| 64 | 66 | inode_unlock(dentry->d_inode); | 
|---|
| 65 | 67 | return ret; | 
|---|
| 66 |  | -} | 
|---|
| 67 |  | -int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | 
|---|
| 68 |  | -	struct file *filp) | 
|---|
| 69 |  | -{ | 
|---|
| 70 |  | -	return do_truncate2(NULL, dentry, length, time_attrs, filp); | 
|---|
| 71 | 68 | } | 
|---|
| 72 | 69 |  | 
|---|
| 73 | 70 | long vfs_truncate(const struct path *path, loff_t length) | 
|---|
| 74 | 71 | { | 
|---|
| 75 | 72 | struct inode *inode; | 
|---|
| 76 |  | -	struct vfsmount *mnt; | 
|---|
| 77 | 73 | long error; | 
|---|
| 78 | 74 |  | 
|---|
| 79 | 75 | inode = path->dentry->d_inode; | 
|---|
| 80 |  | -	mnt = path->mnt; | 
|---|
| 81 | 76 |  | 
|---|
| 82 | 77 | /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ | 
|---|
| 83 | 78 | if (S_ISDIR(inode->i_mode)) | 
|---|
| .. | .. | 
|---|
| 89 | 84 | if (error) | 
|---|
| 90 | 85 | goto out; | 
|---|
| 91 | 86 |  | 
|---|
| 92 |  | -	error = inode_permission2(mnt, inode, MAY_WRITE); | 
|---|
|  | 87 | +	error = inode_permission(inode, MAY_WRITE); | 
|---|
| 93 | 88 | if (error) | 
|---|
| 94 | 89 | goto mnt_drop_write_and_out; | 
|---|
| 95 | 90 |  | 
|---|
| .. | .. | 
|---|
| 113 | 108 | if (!error) | 
|---|
| 114 | 109 | error = security_path_truncate(path); | 
|---|
| 115 | 110 | if (!error) | 
|---|
| 116 |  | -		error = do_truncate2(mnt, path->dentry, length, 0, NULL); | 
|---|
|  | 111 | +		error = do_truncate(path->dentry, length, 0, NULL); | 
|---|
| 117 | 112 |  | 
|---|
| 118 | 113 | put_write_and_out: | 
|---|
| 119 | 114 | put_write_access(inode); | 
|---|
| .. | .. | 
|---|
| 162 | 157 | { | 
|---|
| 163 | 158 | struct inode *inode; | 
|---|
| 164 | 159 | struct dentry *dentry; | 
|---|
| 165 |  | -	struct vfsmount *mnt; | 
|---|
| 166 | 160 | struct fd f; | 
|---|
| 167 | 161 | int error; | 
|---|
| 168 | 162 |  | 
|---|
| .. | .. | 
|---|
| 179 | 173 | small = 0; | 
|---|
| 180 | 174 |  | 
|---|
| 181 | 175 | dentry = f.file->f_path.dentry; | 
|---|
| 182 |  | -	mnt = f.file->f_path.mnt; | 
|---|
| 183 | 176 | inode = dentry->d_inode; | 
|---|
| 184 | 177 | error = -EINVAL; | 
|---|
| 185 | 178 | if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE)) | 
|---|
| .. | .. | 
|---|
| 200 | 193 | if (!error) | 
|---|
| 201 | 194 | error = security_path_truncate(&f.file->f_path); | 
|---|
| 202 | 195 | if (!error) | 
|---|
| 203 |  | -		error = do_truncate2(mnt, dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); | 
|---|
|  | 196 | +		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); | 
|---|
| 204 | 197 | sb_end_write(inode->i_sb); | 
|---|
| 205 | 198 | out_putf: | 
|---|
| 206 | 199 | fdput(f); | 
|---|
| .. | .. | 
|---|
| 353 | 346 | * We do this by temporarily clearing all FS-related capabilities and | 
|---|
| 354 | 347 | * switching the fsuid/fsgid around to the real ones. | 
|---|
| 355 | 348 | */ | 
|---|
| 356 |  | -long do_faccessat(int dfd, const char __user *filename, int mode) | 
|---|
|  | 349 | +static const struct cred *access_override_creds(void) | 
|---|
| 357 | 350 | { | 
|---|
| 358 | 351 | const struct cred *old_cred; | 
|---|
| 359 | 352 | struct cred *override_cred; | 
|---|
| 360 |  | -	struct path path; | 
|---|
| 361 |  | -	struct inode *inode; | 
|---|
| 362 |  | -	struct vfsmount *mnt; | 
|---|
| 363 |  | -	int res; | 
|---|
| 364 |  | -	unsigned int lookup_flags = LOOKUP_FOLLOW; | 
|---|
| 365 |  | - | 
|---|
| 366 |  | -	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */ | 
|---|
| 367 |  | -		return -EINVAL; | 
|---|
| 368 | 353 |  | 
|---|
| 369 | 354 | override_cred = prepare_creds(); | 
|---|
| 370 | 355 | if (!override_cred) | 
|---|
| 371 |  | -		return -ENOMEM; | 
|---|
|  | 356 | +		return NULL; | 
|---|
| 372 | 357 |  | 
|---|
| 373 | 358 | override_cred->fsuid = override_cred->uid; | 
|---|
| 374 | 359 | override_cred->fsgid = override_cred->gid; | 
|---|
| .. | .. | 
|---|
| 403 | 388 | override_cred->non_rcu = 1; | 
|---|
| 404 | 389 |  | 
|---|
| 405 | 390 | old_cred = override_creds(override_cred); | 
|---|
|  | 391 | + | 
|---|
|  | 392 | +	/* override_cred() gets its own ref */ | 
|---|
|  | 393 | +	put_cred(override_cred); | 
|---|
|  | 394 | + | 
|---|
|  | 395 | +	return old_cred; | 
|---|
|  | 396 | +} | 
|---|
|  | 397 | + | 
|---|
|  | 398 | +static long do_faccessat(int dfd, const char __user *filename, int mode, int flags) | 
|---|
|  | 399 | +{ | 
|---|
|  | 400 | +	struct path path; | 
|---|
|  | 401 | +	struct inode *inode; | 
|---|
|  | 402 | +	int res; | 
|---|
|  | 403 | +	unsigned int lookup_flags = LOOKUP_FOLLOW; | 
|---|
|  | 404 | +	const struct cred *old_cred = NULL; | 
|---|
|  | 405 | + | 
|---|
|  | 406 | +	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */ | 
|---|
|  | 407 | +		return -EINVAL; | 
|---|
|  | 408 | + | 
|---|
|  | 409 | +	if (flags & ~(AT_EACCESS | AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) | 
|---|
|  | 410 | +		return -EINVAL; | 
|---|
|  | 411 | + | 
|---|
|  | 412 | +	if (flags & AT_SYMLINK_NOFOLLOW) | 
|---|
|  | 413 | +		lookup_flags &= ~LOOKUP_FOLLOW; | 
|---|
|  | 414 | +	if (flags & AT_EMPTY_PATH) | 
|---|
|  | 415 | +		lookup_flags |= LOOKUP_EMPTY; | 
|---|
|  | 416 | + | 
|---|
|  | 417 | +	if (!(flags & AT_EACCESS)) { | 
|---|
|  | 418 | +		old_cred = access_override_creds(); | 
|---|
|  | 419 | +		if (!old_cred) | 
|---|
|  | 420 | +			return -ENOMEM; | 
|---|
|  | 421 | +	} | 
|---|
|  | 422 | + | 
|---|
| 406 | 423 | retry: | 
|---|
| 407 | 424 | res = user_path_at(dfd, filename, lookup_flags, &path); | 
|---|
| 408 | 425 | if (res) | 
|---|
| 409 | 426 | goto out; | 
|---|
| 410 | 427 |  | 
|---|
| 411 | 428 | inode = d_backing_inode(path.dentry); | 
|---|
| 412 |  | -	mnt = path.mnt; | 
|---|
| 413 | 429 |  | 
|---|
| 414 | 430 | if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { | 
|---|
| 415 | 431 | /* | 
|---|
| .. | .. | 
|---|
| 421 | 437 | goto out_path_release; | 
|---|
| 422 | 438 | } | 
|---|
| 423 | 439 |  | 
|---|
| 424 |  | -	res = inode_permission2(mnt, inode, mode | MAY_ACCESS); | 
|---|
|  | 440 | +	res = inode_permission(inode, mode | MAY_ACCESS); | 
|---|
| 425 | 441 | /* SuS v2 requires we report a read only fs too */ | 
|---|
| 426 | 442 | if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) | 
|---|
| 427 | 443 | goto out_path_release; | 
|---|
| .. | .. | 
|---|
| 445 | 461 | goto retry; | 
|---|
| 446 | 462 | } | 
|---|
| 447 | 463 | out: | 
|---|
| 448 |  | -	revert_creds(old_cred); | 
|---|
| 449 |  | -	put_cred(override_cred); | 
|---|
|  | 464 | +	if (old_cred) | 
|---|
|  | 465 | +		revert_creds(old_cred); | 
|---|
|  | 466 | + | 
|---|
| 450 | 467 | return res; | 
|---|
| 451 | 468 | } | 
|---|
| 452 | 469 |  | 
|---|
| 453 | 470 | SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) | 
|---|
| 454 | 471 | { | 
|---|
| 455 |  | -	return do_faccessat(dfd, filename, mode); | 
|---|
|  | 472 | +	return do_faccessat(dfd, filename, mode, 0); | 
|---|
|  | 473 | +} | 
|---|
|  | 474 | + | 
|---|
|  | 475 | +SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode, | 
|---|
|  | 476 | +		int, flags) | 
|---|
|  | 477 | +{ | 
|---|
|  | 478 | +	return do_faccessat(dfd, filename, mode, flags); | 
|---|
| 456 | 479 | } | 
|---|
| 457 | 480 |  | 
|---|
| 458 | 481 | SYSCALL_DEFINE2(access, const char __user *, filename, int, mode) | 
|---|
| 459 | 482 | { | 
|---|
| 460 |  | -	return do_faccessat(AT_FDCWD, filename, mode); | 
|---|
|  | 483 | +	return do_faccessat(AT_FDCWD, filename, mode, 0); | 
|---|
| 461 | 484 | } | 
|---|
| 462 | 485 |  | 
|---|
| 463 |  | -int ksys_chdir(const char __user *filename) | 
|---|
|  | 486 | +SYSCALL_DEFINE1(chdir, const char __user *, filename) | 
|---|
| 464 | 487 | { | 
|---|
| 465 | 488 | struct path path; | 
|---|
| 466 | 489 | int error; | 
|---|
| .. | .. | 
|---|
| 470 | 493 | if (error) | 
|---|
| 471 | 494 | goto out; | 
|---|
| 472 | 495 |  | 
|---|
| 473 |  | -	error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); | 
|---|
|  | 496 | +	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); | 
|---|
| 474 | 497 | if (error) | 
|---|
| 475 | 498 | goto dput_and_out; | 
|---|
| 476 | 499 |  | 
|---|
| .. | .. | 
|---|
| 486 | 509 | return error; | 
|---|
| 487 | 510 | } | 
|---|
| 488 | 511 |  | 
|---|
| 489 |  | -SYSCALL_DEFINE1(chdir, const char __user *, filename) | 
|---|
| 490 |  | -{ | 
|---|
| 491 |  | -	return ksys_chdir(filename); | 
|---|
| 492 |  | -} | 
|---|
| 493 |  | - | 
|---|
| 494 | 512 | SYSCALL_DEFINE1(fchdir, unsigned int, fd) | 
|---|
| 495 | 513 | { | 
|---|
| 496 | 514 | struct fd f = fdget_raw(fd); | 
|---|
| .. | .. | 
|---|
| 504 | 522 | if (!d_can_lookup(f.file->f_path.dentry)) | 
|---|
| 505 | 523 | goto out_putf; | 
|---|
| 506 | 524 |  | 
|---|
| 507 |  | -	error = inode_permission2(f.file->f_path.mnt, file_inode(f.file), | 
|---|
| 508 |  | -				MAY_EXEC | MAY_CHDIR); | 
|---|
|  | 525 | +	error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR); | 
|---|
| 509 | 526 | if (!error) | 
|---|
| 510 | 527 | set_fs_pwd(current->fs, &f.file->f_path); | 
|---|
| 511 | 528 | out_putf: | 
|---|
| .. | .. | 
|---|
| 514 | 531 | return error; | 
|---|
| 515 | 532 | } | 
|---|
| 516 | 533 |  | 
|---|
| 517 |  | -int ksys_chroot(const char __user *filename) | 
|---|
|  | 534 | +SYSCALL_DEFINE1(chroot, const char __user *, filename) | 
|---|
| 518 | 535 | { | 
|---|
| 519 | 536 | struct path path; | 
|---|
| 520 | 537 | int error; | 
|---|
| .. | .. | 
|---|
| 524 | 541 | if (error) | 
|---|
| 525 | 542 | goto out; | 
|---|
| 526 | 543 |  | 
|---|
| 527 |  | -	error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); | 
|---|
|  | 544 | +	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); | 
|---|
| 528 | 545 | if (error) | 
|---|
| 529 | 546 | goto dput_and_out; | 
|---|
| 530 | 547 |  | 
|---|
| .. | .. | 
|---|
| 547 | 564 | return error; | 
|---|
| 548 | 565 | } | 
|---|
| 549 | 566 |  | 
|---|
| 550 |  | -SYSCALL_DEFINE1(chroot, const char __user *, filename) | 
|---|
| 551 |  | -{ | 
|---|
| 552 |  | -	return ksys_chroot(filename); | 
|---|
| 553 |  | -} | 
|---|
| 554 |  | - | 
|---|
| 555 |  | -static int chmod_common(const struct path *path, umode_t mode) | 
|---|
|  | 567 | +int chmod_common(const struct path *path, umode_t mode) | 
|---|
| 556 | 568 | { | 
|---|
| 557 | 569 | struct inode *inode = path->dentry->d_inode; | 
|---|
| 558 | 570 | struct inode *delegated_inode = NULL; | 
|---|
| .. | .. | 
|---|
| 569 | 581 | goto out_unlock; | 
|---|
| 570 | 582 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 
|---|
| 571 | 583 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 
|---|
| 572 |  | -	error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode); | 
|---|
|  | 584 | +	error = notify_change(path->dentry, &newattrs, &delegated_inode); | 
|---|
| 573 | 585 | out_unlock: | 
|---|
| 574 | 586 | inode_unlock(inode); | 
|---|
| 575 | 587 | if (delegated_inode) { | 
|---|
| .. | .. | 
|---|
| 581 | 593 | return error; | 
|---|
| 582 | 594 | } | 
|---|
| 583 | 595 |  | 
|---|
| 584 |  | -int ksys_fchmod(unsigned int fd, umode_t mode) | 
|---|
|  | 596 | +int vfs_fchmod(struct file *file, umode_t mode) | 
|---|
|  | 597 | +{ | 
|---|
|  | 598 | +	audit_file(file); | 
|---|
|  | 599 | +	return chmod_common(&file->f_path, mode); | 
|---|
|  | 600 | +} | 
|---|
|  | 601 | + | 
|---|
|  | 602 | +SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) | 
|---|
| 585 | 603 | { | 
|---|
| 586 | 604 | struct fd f = fdget(fd); | 
|---|
| 587 | 605 | int err = -EBADF; | 
|---|
| 588 | 606 |  | 
|---|
| 589 | 607 | if (f.file) { | 
|---|
| 590 |  | -		audit_file(f.file); | 
|---|
| 591 |  | -		err = chmod_common(&f.file->f_path, mode); | 
|---|
|  | 608 | +		err = vfs_fchmod(f.file, mode); | 
|---|
| 592 | 609 | fdput(f); | 
|---|
| 593 | 610 | } | 
|---|
| 594 | 611 | return err; | 
|---|
| 595 | 612 | } | 
|---|
| 596 | 613 |  | 
|---|
| 597 |  | -SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) | 
|---|
| 598 |  | -{ | 
|---|
| 599 |  | -	return ksys_fchmod(fd, mode); | 
|---|
| 600 |  | -} | 
|---|
| 601 |  | - | 
|---|
| 602 |  | -int do_fchmodat(int dfd, const char __user *filename, umode_t mode) | 
|---|
|  | 614 | +static int do_fchmodat(int dfd, const char __user *filename, umode_t mode) | 
|---|
| 603 | 615 | { | 
|---|
| 604 | 616 | struct path path; | 
|---|
| 605 | 617 | int error; | 
|---|
| .. | .. | 
|---|
| 628 | 640 | return do_fchmodat(AT_FDCWD, filename, mode); | 
|---|
| 629 | 641 | } | 
|---|
| 630 | 642 |  | 
|---|
| 631 |  | -static int chown_common(const struct path *path, uid_t user, gid_t group) | 
|---|
|  | 643 | +int chown_common(const struct path *path, uid_t user, gid_t group) | 
|---|
| 632 | 644 | { | 
|---|
| 633 | 645 | struct inode *inode = path->dentry->d_inode; | 
|---|
| 634 | 646 | struct inode *delegated_inode = NULL; | 
|---|
| .. | .. | 
|---|
| 660 | 672 | inode_lock(inode); | 
|---|
| 661 | 673 | error = security_path_chown(path, uid, gid); | 
|---|
| 662 | 674 | if (!error) | 
|---|
| 663 |  | -		error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode); | 
|---|
|  | 675 | +		error = notify_change(path->dentry, &newattrs, &delegated_inode); | 
|---|
| 664 | 676 | inode_unlock(inode); | 
|---|
| 665 | 677 | if (delegated_inode) { | 
|---|
| 666 | 678 | error = break_deleg_wait(&delegated_inode); | 
|---|
| .. | .. | 
|---|
| 719 | 731 | AT_SYMLINK_NOFOLLOW); | 
|---|
| 720 | 732 | } | 
|---|
| 721 | 733 |  | 
|---|
|  | 734 | +int vfs_fchown(struct file *file, uid_t user, gid_t group) | 
|---|
|  | 735 | +{ | 
|---|
|  | 736 | +	int error; | 
|---|
|  | 737 | + | 
|---|
|  | 738 | +	error = mnt_want_write_file(file); | 
|---|
|  | 739 | +	if (error) | 
|---|
|  | 740 | +		return error; | 
|---|
|  | 741 | +	audit_file(file); | 
|---|
|  | 742 | +	error = chown_common(&file->f_path, user, group); | 
|---|
|  | 743 | +	mnt_drop_write_file(file); | 
|---|
|  | 744 | +	return error; | 
|---|
|  | 745 | +} | 
|---|
|  | 746 | + | 
|---|
| 722 | 747 | int ksys_fchown(unsigned int fd, uid_t user, gid_t group) | 
|---|
| 723 | 748 | { | 
|---|
| 724 | 749 | struct fd f = fdget(fd); | 
|---|
| 725 | 750 | int error = -EBADF; | 
|---|
| 726 | 751 |  | 
|---|
| 727 |  | -	if (!f.file) | 
|---|
| 728 |  | -		goto out; | 
|---|
| 729 |  | - | 
|---|
| 730 |  | -	error = mnt_want_write_file(f.file); | 
|---|
| 731 |  | -	if (error) | 
|---|
| 732 |  | -		goto out_fput; | 
|---|
| 733 |  | -	audit_file(f.file); | 
|---|
| 734 |  | -	error = chown_common(&f.file->f_path, user, group); | 
|---|
| 735 |  | -	mnt_drop_write_file(f.file); | 
|---|
| 736 |  | -out_fput: | 
|---|
| 737 |  | -	fdput(f); | 
|---|
| 738 |  | -out: | 
|---|
|  | 752 | +	if (f.file) { | 
|---|
|  | 753 | +		error = vfs_fchown(f.file, user, group); | 
|---|
|  | 754 | +		fdput(f); | 
|---|
|  | 755 | +	} | 
|---|
| 739 | 756 | return error; | 
|---|
| 740 | 757 | } | 
|---|
| 741 | 758 |  | 
|---|
| .. | .. | 
|---|
| 754 | 771 | path_get(&f->f_path); | 
|---|
| 755 | 772 | f->f_inode = inode; | 
|---|
| 756 | 773 | f->f_mapping = inode->i_mapping; | 
|---|
| 757 |  | - | 
|---|
| 758 |  | -	/* Ensure that we skip any errors that predate opening of the file */ | 
|---|
| 759 | 774 | f->f_wb_err = filemap_sample_wb_err(f->f_mapping); | 
|---|
|  | 775 | +	f->f_sb_err = file_sample_sb_err(f); | 
|---|
| 760 | 776 |  | 
|---|
| 761 | 777 | if (unlikely(f->f_flags & O_PATH)) { | 
|---|
| 762 | 778 | f->f_mode = FMODE_PATH | FMODE_OPENED; | 
|---|
| 763 | 779 | f->f_op = &empty_fops; | 
|---|
| 764 | 780 | return 0; | 
|---|
| 765 |  | -	} | 
|---|
| 766 |  | - | 
|---|
| 767 |  | -	/* Any file opened for execve()/uselib() has to be a regular file. */ | 
|---|
| 768 |  | -	if (unlikely(f->f_flags & FMODE_EXEC && !S_ISREG(inode->i_mode))) { | 
|---|
| 769 |  | -		error = -EACCES; | 
|---|
| 770 |  | -		goto cleanup_file; | 
|---|
| 771 | 781 | } | 
|---|
| 772 | 782 |  | 
|---|
| 773 | 783 | if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { | 
|---|
| .. | .. | 
|---|
| 787 | 797 | f->f_mode |= FMODE_ATOMIC_POS; | 
|---|
| 788 | 798 |  | 
|---|
| 789 | 799 | f->f_op = fops_get(inode->i_fop); | 
|---|
| 790 |  | -	if (unlikely(WARN_ON(!f->f_op))) { | 
|---|
|  | 800 | +	if (WARN_ON(!f->f_op)) { | 
|---|
| 791 | 801 | error = -ENODEV; | 
|---|
| 792 | 802 | goto cleanup_all; | 
|---|
| 793 | 803 | } | 
|---|
|  | 804 | +	trace_android_vh_check_file_open(f); | 
|---|
| 794 | 805 |  | 
|---|
| 795 | 806 | error = security_file_open(f); | 
|---|
| 796 | 807 | if (error) | 
|---|
| .. | .. | 
|---|
| 829 | 840 | if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) | 
|---|
| 830 | 841 | return -EINVAL; | 
|---|
| 831 | 842 | } | 
|---|
|  | 843 | + | 
|---|
|  | 844 | +	/* | 
|---|
|  | 845 | +	 * XXX: Huge page cache doesn't support writing yet. Drop all page | 
|---|
|  | 846 | +	 * cache for this file before processing writes. | 
|---|
|  | 847 | +	 */ | 
|---|
|  | 848 | +	if (f->f_mode & FMODE_WRITE) { | 
|---|
|  | 849 | +		/* | 
|---|
|  | 850 | +		 * Paired with smp_mb() in collapse_file() to ensure nr_thps | 
|---|
|  | 851 | +		 * is up to date and the update to i_writecount by | 
|---|
|  | 852 | +		 * get_write_access() is visible. Ensures subsequent insertion | 
|---|
|  | 853 | +		 * of THPs into the page cache will fail. | 
|---|
|  | 854 | +		 */ | 
|---|
|  | 855 | +		smp_mb(); | 
|---|
|  | 856 | +		if (filemap_nr_thps(inode->i_mapping)) | 
|---|
|  | 857 | +			truncate_pagecache(inode, 0); | 
|---|
|  | 858 | +	} | 
|---|
|  | 859 | + | 
|---|
| 832 | 860 | return 0; | 
|---|
| 833 | 861 |  | 
|---|
| 834 | 862 | cleanup_all: | 
|---|
| .. | .. | 
|---|
| 955 | 983 | } | 
|---|
| 956 | 984 | EXPORT_SYMBOL(open_with_fake_path); | 
|---|
| 957 | 985 |  | 
|---|
| 958 |  | -static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) | 
|---|
|  | 986 | +#define WILL_CREATE(flags)	(flags & (O_CREAT | __O_TMPFILE)) | 
|---|
|  | 987 | +#define O_PATH_FLAGS		(O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) | 
|---|
|  | 988 | + | 
|---|
|  | 989 | +inline struct open_how build_open_how(int flags, umode_t mode) | 
|---|
| 959 | 990 | { | 
|---|
|  | 991 | +	struct open_how how = { | 
|---|
|  | 992 | +		.flags = flags & VALID_OPEN_FLAGS, | 
|---|
|  | 993 | +		.mode = mode & S_IALLUGO, | 
|---|
|  | 994 | +	}; | 
|---|
|  | 995 | + | 
|---|
|  | 996 | +	/* O_PATH beats everything else. */ | 
|---|
|  | 997 | +	if (how.flags & O_PATH) | 
|---|
|  | 998 | +		how.flags &= O_PATH_FLAGS; | 
|---|
|  | 999 | +	/* Modes should only be set for create-like flags. */ | 
|---|
|  | 1000 | +	if (!WILL_CREATE(how.flags)) | 
|---|
|  | 1001 | +		how.mode = 0; | 
|---|
|  | 1002 | +	return how; | 
|---|
|  | 1003 | +} | 
|---|
|  | 1004 | + | 
|---|
|  | 1005 | +inline int build_open_flags(const struct open_how *how, struct open_flags *op) | 
|---|
|  | 1006 | +{ | 
|---|
|  | 1007 | +	u64 flags = how->flags; | 
|---|
|  | 1008 | +	u64 strip = FMODE_NONOTIFY | O_CLOEXEC; | 
|---|
| 960 | 1009 | int lookup_flags = 0; | 
|---|
| 961 | 1010 | int acc_mode = ACC_MODE(flags); | 
|---|
| 962 | 1011 |  | 
|---|
|  | 1012 | +	BUILD_BUG_ON_MSG(upper_32_bits(VALID_OPEN_FLAGS), | 
|---|
|  | 1013 | +			 "struct open_flags doesn't yet handle flags > 32 bits"); | 
|---|
|  | 1014 | + | 
|---|
| 963 | 1015 | /* | 
|---|
| 964 |  | -	 * Clear out all open flags we don't know about so that we don't report | 
|---|
| 965 |  | -	 * them in fcntl(F_GETFD) or similar interfaces. | 
|---|
|  | 1016 | +	 * Strip flags that either shouldn't be set by userspace like | 
|---|
|  | 1017 | +	 * FMODE_NONOTIFY or that aren't relevant in determining struct | 
|---|
|  | 1018 | +	 * open_flags like O_CLOEXEC. | 
|---|
| 966 | 1019 | */ | 
|---|
| 967 |  | -	flags &= VALID_OPEN_FLAGS; | 
|---|
|  | 1020 | +	flags &= ~strip; | 
|---|
| 968 | 1021 |  | 
|---|
| 969 |  | -	if (flags & (O_CREAT | __O_TMPFILE)) | 
|---|
| 970 |  | -		op->mode = (mode & S_IALLUGO) | S_IFREG; | 
|---|
| 971 |  | -	else | 
|---|
|  | 1022 | +	/* | 
|---|
|  | 1023 | +	 * Older syscalls implicitly clear all of the invalid flags or argument | 
|---|
|  | 1024 | +	 * values before calling build_open_flags(), but openat2(2) checks all | 
|---|
|  | 1025 | +	 * of its arguments. | 
|---|
|  | 1026 | +	 */ | 
|---|
|  | 1027 | +	if (flags & ~VALID_OPEN_FLAGS) | 
|---|
|  | 1028 | +		return -EINVAL; | 
|---|
|  | 1029 | +	if (how->resolve & ~VALID_RESOLVE_FLAGS) | 
|---|
|  | 1030 | +		return -EINVAL; | 
|---|
|  | 1031 | + | 
|---|
|  | 1032 | +	/* Scoping flags are mutually exclusive. */ | 
|---|
|  | 1033 | +	if ((how->resolve & RESOLVE_BENEATH) && (how->resolve & RESOLVE_IN_ROOT)) | 
|---|
|  | 1034 | +		return -EINVAL; | 
|---|
|  | 1035 | + | 
|---|
|  | 1036 | +	/* Deal with the mode. */ | 
|---|
|  | 1037 | +	if (WILL_CREATE(flags)) { | 
|---|
|  | 1038 | +		if (how->mode & ~S_IALLUGO) | 
|---|
|  | 1039 | +			return -EINVAL; | 
|---|
|  | 1040 | +		op->mode = how->mode | S_IFREG; | 
|---|
|  | 1041 | +	} else { | 
|---|
|  | 1042 | +		if (how->mode != 0) | 
|---|
|  | 1043 | +			return -EINVAL; | 
|---|
| 972 | 1044 | op->mode = 0; | 
|---|
|  | 1045 | +	} | 
|---|
| 973 | 1046 |  | 
|---|
| 974 |  | -	/* Must never be set by userspace */ | 
|---|
| 975 |  | -	flags &= ~FMODE_NONOTIFY & ~O_CLOEXEC; | 
|---|
|  | 1047 | +	/* | 
|---|
|  | 1048 | +	 * In order to ensure programs get explicit errors when trying to use | 
|---|
|  | 1049 | +	 * O_TMPFILE on old kernels, O_TMPFILE is implemented such that it | 
|---|
|  | 1050 | +	 * looks like (O_DIRECTORY|O_RDWR & ~O_CREAT) to old kernels. But we | 
|---|
|  | 1051 | +	 * have to require userspace to explicitly set it. | 
|---|
|  | 1052 | +	 */ | 
|---|
|  | 1053 | +	if (flags & __O_TMPFILE) { | 
|---|
|  | 1054 | +		if ((flags & O_TMPFILE_MASK) != O_TMPFILE) | 
|---|
|  | 1055 | +			return -EINVAL; | 
|---|
|  | 1056 | +		if (!(acc_mode & MAY_WRITE)) | 
|---|
|  | 1057 | +			return -EINVAL; | 
|---|
|  | 1058 | +	} | 
|---|
|  | 1059 | +	if (flags & O_PATH) { | 
|---|
|  | 1060 | +		/* O_PATH only permits certain other flags to be set. */ | 
|---|
|  | 1061 | +		if (flags & ~O_PATH_FLAGS) | 
|---|
|  | 1062 | +			return -EINVAL; | 
|---|
|  | 1063 | +		acc_mode = 0; | 
|---|
|  | 1064 | +	} | 
|---|
| 976 | 1065 |  | 
|---|
| 977 | 1066 | /* | 
|---|
| 978 | 1067 | * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only | 
|---|
| .. | .. | 
|---|
| 982 | 1071 | */ | 
|---|
| 983 | 1072 | if (flags & __O_SYNC) | 
|---|
| 984 | 1073 | flags |= O_DSYNC; | 
|---|
| 985 |  | - | 
|---|
| 986 |  | -	if (flags & __O_TMPFILE) { | 
|---|
| 987 |  | -		if ((flags & O_TMPFILE_MASK) != O_TMPFILE) | 
|---|
| 988 |  | -			return -EINVAL; | 
|---|
| 989 |  | -		if (!(acc_mode & MAY_WRITE)) | 
|---|
| 990 |  | -			return -EINVAL; | 
|---|
| 991 |  | -	} else if (flags & O_PATH) { | 
|---|
| 992 |  | -		/* | 
|---|
| 993 |  | -		 * If we have O_PATH in the open flag. Then we | 
|---|
| 994 |  | -		 * cannot have anything other than the below set of flags | 
|---|
| 995 |  | -		 */ | 
|---|
| 996 |  | -		flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; | 
|---|
| 997 |  | -		acc_mode = 0; | 
|---|
| 998 |  | -	} | 
|---|
| 999 | 1074 |  | 
|---|
| 1000 | 1075 | op->open_flag = flags; | 
|---|
| 1001 | 1076 |  | 
|---|
| .. | .. | 
|---|
| 1014 | 1089 |  | 
|---|
| 1015 | 1090 | if (flags & O_CREAT) { | 
|---|
| 1016 | 1091 | op->intent |= LOOKUP_CREATE; | 
|---|
| 1017 |  | -		if (flags & O_EXCL) | 
|---|
|  | 1092 | +		if (flags & O_EXCL) { | 
|---|
| 1018 | 1093 | op->intent |= LOOKUP_EXCL; | 
|---|
|  | 1094 | +			flags |= O_NOFOLLOW; | 
|---|
|  | 1095 | +		} | 
|---|
| 1019 | 1096 | } | 
|---|
| 1020 | 1097 |  | 
|---|
| 1021 | 1098 | if (flags & O_DIRECTORY) | 
|---|
| 1022 | 1099 | lookup_flags |= LOOKUP_DIRECTORY; | 
|---|
| 1023 | 1100 | if (!(flags & O_NOFOLLOW)) | 
|---|
| 1024 | 1101 | lookup_flags |= LOOKUP_FOLLOW; | 
|---|
|  | 1102 | + | 
|---|
|  | 1103 | +	if (how->resolve & RESOLVE_NO_XDEV) | 
|---|
|  | 1104 | +		lookup_flags |= LOOKUP_NO_XDEV; | 
|---|
|  | 1105 | +	if (how->resolve & RESOLVE_NO_MAGICLINKS) | 
|---|
|  | 1106 | +		lookup_flags |= LOOKUP_NO_MAGICLINKS; | 
|---|
|  | 1107 | +	if (how->resolve & RESOLVE_NO_SYMLINKS) | 
|---|
|  | 1108 | +		lookup_flags |= LOOKUP_NO_SYMLINKS; | 
|---|
|  | 1109 | +	if (how->resolve & RESOLVE_BENEATH) | 
|---|
|  | 1110 | +		lookup_flags |= LOOKUP_BENEATH; | 
|---|
|  | 1111 | +	if (how->resolve & RESOLVE_IN_ROOT) | 
|---|
|  | 1112 | +		lookup_flags |= LOOKUP_IN_ROOT; | 
|---|
|  | 1113 | +	if (how->resolve & RESOLVE_CACHED) { | 
|---|
|  | 1114 | +		/* Don't bother even trying for create/truncate/tmpfile open */ | 
|---|
|  | 1115 | +		if (flags & (O_TRUNC | O_CREAT | O_TMPFILE)) | 
|---|
|  | 1116 | +			return -EAGAIN; | 
|---|
|  | 1117 | +		lookup_flags |= LOOKUP_CACHED; | 
|---|
|  | 1118 | +	} | 
|---|
|  | 1119 | + | 
|---|
| 1025 | 1120 | op->lookup_flags = lookup_flags; | 
|---|
| 1026 | 1121 | return 0; | 
|---|
| 1027 | 1122 | } | 
|---|
| .. | .. | 
|---|
| 1040 | 1135 | struct file *file_open_name(struct filename *name, int flags, umode_t mode) | 
|---|
| 1041 | 1136 | { | 
|---|
| 1042 | 1137 | struct open_flags op; | 
|---|
| 1043 |  | -	int err = build_open_flags(flags, mode, &op); | 
|---|
| 1044 |  | -	return err ? ERR_PTR(err) : do_filp_open(AT_FDCWD, name, &op); | 
|---|
|  | 1138 | +	struct open_how how = build_open_how(flags, mode); | 
|---|
|  | 1139 | +	int err = build_open_flags(&how, &op); | 
|---|
|  | 1140 | +	if (err) | 
|---|
|  | 1141 | +		return ERR_PTR(err); | 
|---|
|  | 1142 | +	return do_filp_open(AT_FDCWD, name, &op); | 
|---|
| 1045 | 1143 | } | 
|---|
| 1046 | 1144 |  | 
|---|
| 1047 | 1145 | /** | 
|---|
| .. | .. | 
|---|
| 1066 | 1164 | } | 
|---|
| 1067 | 1165 | return file; | 
|---|
| 1068 | 1166 | } | 
|---|
| 1069 |  | -EXPORT_SYMBOL(filp_open); | 
|---|
|  | 1167 | +EXPORT_SYMBOL_NS(filp_open, ANDROID_GKI_VFS_EXPORT_ONLY); | 
|---|
|  | 1168 | + | 
|---|
|  | 1169 | +/* ANDROID: Allow drivers to open only block files from kernel mode */ | 
|---|
|  | 1170 | +struct file *filp_open_block(const char *filename, int flags, umode_t mode) | 
|---|
|  | 1171 | +{ | 
|---|
|  | 1172 | +	struct file *file; | 
|---|
|  | 1173 | + | 
|---|
|  | 1174 | +	file = filp_open(filename, flags, mode); | 
|---|
|  | 1175 | +	if (IS_ERR(file)) | 
|---|
|  | 1176 | +		goto err_out; | 
|---|
|  | 1177 | + | 
|---|
|  | 1178 | +	/* Drivers should only be allowed to open block devices */ | 
|---|
|  | 1179 | +	if (!S_ISBLK(file->f_mapping->host->i_mode)) { | 
|---|
|  | 1180 | +		filp_close(file, NULL); | 
|---|
|  | 1181 | +		file = ERR_PTR(-ENOTBLK); | 
|---|
|  | 1182 | +	} | 
|---|
|  | 1183 | + | 
|---|
|  | 1184 | +err_out: | 
|---|
|  | 1185 | +	return file; | 
|---|
|  | 1186 | +} | 
|---|
|  | 1187 | +EXPORT_SYMBOL_GPL(filp_open_block); | 
|---|
| 1070 | 1188 |  | 
|---|
| 1071 | 1189 | struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, | 
|---|
| 1072 | 1190 | const char *filename, int flags, umode_t mode) | 
|---|
| 1073 | 1191 | { | 
|---|
| 1074 | 1192 | struct open_flags op; | 
|---|
| 1075 |  | -	int err = build_open_flags(flags, mode, &op); | 
|---|
|  | 1193 | +	struct open_how how = build_open_how(flags, mode); | 
|---|
|  | 1194 | +	int err = build_open_flags(&how, &op); | 
|---|
| 1076 | 1195 | if (err) | 
|---|
| 1077 | 1196 | return ERR_PTR(err); | 
|---|
| 1078 | 1197 | return do_file_open_root(dentry, mnt, filename, &op); | 
|---|
| 1079 | 1198 | } | 
|---|
| 1080 | 1199 | EXPORT_SYMBOL(file_open_root); | 
|---|
| 1081 | 1200 |  | 
|---|
| 1082 |  | -long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) | 
|---|
|  | 1201 | +static long do_sys_openat2(int dfd, const char __user *filename, | 
|---|
|  | 1202 | +			   struct open_how *how) | 
|---|
| 1083 | 1203 | { | 
|---|
| 1084 | 1204 | struct open_flags op; | 
|---|
| 1085 |  | -	int fd = build_open_flags(flags, mode, &op); | 
|---|
|  | 1205 | +	int fd = build_open_flags(how, &op); | 
|---|
| 1086 | 1206 | struct filename *tmp; | 
|---|
| 1087 | 1207 |  | 
|---|
| 1088 | 1208 | if (fd) | 
|---|
| .. | .. | 
|---|
| 1092 | 1212 | if (IS_ERR(tmp)) | 
|---|
| 1093 | 1213 | return PTR_ERR(tmp); | 
|---|
| 1094 | 1214 |  | 
|---|
| 1095 |  | -	fd = get_unused_fd_flags(flags); | 
|---|
|  | 1215 | +	fd = get_unused_fd_flags(how->flags); | 
|---|
| 1096 | 1216 | if (fd >= 0) { | 
|---|
| 1097 | 1217 | struct file *f = do_filp_open(dfd, tmp, &op); | 
|---|
| 1098 | 1218 | if (IS_ERR(f)) { | 
|---|
| .. | .. | 
|---|
| 1107 | 1227 | return fd; | 
|---|
| 1108 | 1228 | } | 
|---|
| 1109 | 1229 |  | 
|---|
|  | 1230 | +long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) | 
|---|
|  | 1231 | +{ | 
|---|
|  | 1232 | +	struct open_how how = build_open_how(flags, mode); | 
|---|
|  | 1233 | +	return do_sys_openat2(dfd, filename, &how); | 
|---|
|  | 1234 | +} | 
|---|
|  | 1235 | + | 
|---|
|  | 1236 | + | 
|---|
| 1110 | 1237 | SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) | 
|---|
| 1111 | 1238 | { | 
|---|
| 1112 | 1239 | if (force_o_largefile()) | 
|---|
| 1113 | 1240 | flags |= O_LARGEFILE; | 
|---|
| 1114 |  | - | 
|---|
| 1115 | 1241 | return do_sys_open(AT_FDCWD, filename, flags, mode); | 
|---|
| 1116 | 1242 | } | 
|---|
| 1117 | 1243 |  | 
|---|
| .. | .. | 
|---|
| 1120 | 1246 | { | 
|---|
| 1121 | 1247 | if (force_o_largefile()) | 
|---|
| 1122 | 1248 | flags |= O_LARGEFILE; | 
|---|
| 1123 |  | - | 
|---|
| 1124 | 1249 | return do_sys_open(dfd, filename, flags, mode); | 
|---|
|  | 1250 | +} | 
|---|
|  | 1251 | + | 
|---|
|  | 1252 | +SYSCALL_DEFINE4(openat2, int, dfd, const char __user *, filename, | 
|---|
|  | 1253 | +		struct open_how __user *, how, size_t, usize) | 
|---|
|  | 1254 | +{ | 
|---|
|  | 1255 | +	int err; | 
|---|
|  | 1256 | +	struct open_how tmp; | 
|---|
|  | 1257 | + | 
|---|
|  | 1258 | +	BUILD_BUG_ON(sizeof(struct open_how) < OPEN_HOW_SIZE_VER0); | 
|---|
|  | 1259 | +	BUILD_BUG_ON(sizeof(struct open_how) != OPEN_HOW_SIZE_LATEST); | 
|---|
|  | 1260 | + | 
|---|
|  | 1261 | +	if (unlikely(usize < OPEN_HOW_SIZE_VER0)) | 
|---|
|  | 1262 | +		return -EINVAL; | 
|---|
|  | 1263 | + | 
|---|
|  | 1264 | +	err = copy_struct_from_user(&tmp, sizeof(tmp), how, usize); | 
|---|
|  | 1265 | +	if (err) | 
|---|
|  | 1266 | +		return err; | 
|---|
|  | 1267 | + | 
|---|
|  | 1268 | +	/* O_LARGEFILE is only allowed for non-O_PATH. */ | 
|---|
|  | 1269 | +	if (!(tmp.flags & O_PATH) && force_o_largefile()) | 
|---|
|  | 1270 | +		tmp.flags |= O_LARGEFILE; | 
|---|
|  | 1271 | + | 
|---|
|  | 1272 | +	return do_sys_openat2(dfd, filename, &tmp); | 
|---|
| 1125 | 1273 | } | 
|---|
| 1126 | 1274 |  | 
|---|
| 1127 | 1275 | #ifdef CONFIG_COMPAT | 
|---|
| .. | .. | 
|---|
| 1152 | 1300 | */ | 
|---|
| 1153 | 1301 | SYSCALL_DEFINE2(creat, const char __user *, pathname, umode_t, mode) | 
|---|
| 1154 | 1302 | { | 
|---|
| 1155 |  | -	return ksys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); | 
|---|
| 1156 |  | -} | 
|---|
|  | 1303 | +	int flags = O_CREAT | O_WRONLY | O_TRUNC; | 
|---|
| 1157 | 1304 |  | 
|---|
|  | 1305 | +	if (force_o_largefile()) | 
|---|
|  | 1306 | +		flags |= O_LARGEFILE; | 
|---|
|  | 1307 | +	return do_sys_open(AT_FDCWD, pathname, flags, mode); | 
|---|
|  | 1308 | +} | 
|---|
| 1158 | 1309 | #endif | 
|---|
| 1159 | 1310 |  | 
|---|
| 1160 | 1311 | /* | 
|---|
| .. | .. | 
|---|
| 1202 | 1353 | return retval; | 
|---|
| 1203 | 1354 | } | 
|---|
| 1204 | 1355 |  | 
|---|
|  | 1356 | +/** | 
|---|
|  | 1357 | + * close_range() - Close all file descriptors in a given range. | 
|---|
|  | 1358 | + * | 
|---|
|  | 1359 | + * @fd:     starting file descriptor to close | 
|---|
|  | 1360 | + * @max_fd: last file descriptor to close | 
|---|
|  | 1361 | + * @flags:  reserved for future extensions | 
|---|
|  | 1362 | + * | 
|---|
|  | 1363 | + * This closes a range of file descriptors. All file descriptors | 
|---|
|  | 1364 | + * from @fd up to and including @max_fd are closed. | 
|---|
|  | 1365 | + * Currently, errors to close a given file descriptor are ignored. | 
|---|
|  | 1366 | + */ | 
|---|
|  | 1367 | +SYSCALL_DEFINE3(close_range, unsigned int, fd, unsigned int, max_fd, | 
|---|
|  | 1368 | +		unsigned int, flags) | 
|---|
|  | 1369 | +{ | 
|---|
|  | 1370 | +	return __close_range(fd, max_fd, flags); | 
|---|
|  | 1371 | +} | 
|---|
|  | 1372 | + | 
|---|
| 1205 | 1373 | /* | 
|---|
| 1206 | 1374 | * This routine simulates a hangup on the tty, to arrange that users | 
|---|
| 1207 | 1375 | * are given clean terminals at login time. | 
|---|
| .. | .. | 
|---|
| 1228 | 1396 | return 0; | 
|---|
| 1229 | 1397 | } | 
|---|
| 1230 | 1398 |  | 
|---|
| 1231 |  | -EXPORT_SYMBOL(generic_file_open); | 
|---|
|  | 1399 | +EXPORT_SYMBOL_NS(generic_file_open, ANDROID_GKI_VFS_EXPORT_ONLY); | 
|---|
| 1232 | 1400 |  | 
|---|
| 1233 | 1401 | /* | 
|---|
| 1234 | 1402 | * This is used by subsystems that don't want seekable | 
|---|
| .. | .. | 
|---|
| 1247 | 1415 | /* | 
|---|
| 1248 | 1416 | * stream_open is used by subsystems that want stream-like file descriptors. | 
|---|
| 1249 | 1417 | * Such file descriptors are not seekable and don't have notion of position | 
|---|
| 1250 |  | - * (file.f_pos is always 0). Contrary to file descriptors of other regular | 
|---|
| 1251 |  | - * files, .read() and .write() can run simultaneously. | 
|---|
|  | 1418 | + * (file.f_pos is always 0 and ppos passed to .read()/.write() is always NULL). | 
|---|
|  | 1419 | + * Contrary to file descriptors of other regular files, .read() and .write() | 
|---|
|  | 1420 | + * can run simultaneously. | 
|---|
| 1252 | 1421 | * | 
|---|
| 1253 | 1422 | * stream_open never fails and is marked to return int so that it could be | 
|---|
| 1254 | 1423 | * directly used as file_operations.open . | 
|---|