diff options
Diffstat (limited to 'fs/open.c')
| -rw-r--r-- | fs/open.c | 59 |
1 files changed, 27 insertions, 32 deletions
| @@ -425,39 +425,33 @@ out: | |||
| 425 | */ | 425 | */ |
| 426 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | 426 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) |
| 427 | { | 427 | { |
| 428 | const struct cred *old_cred; | ||
| 429 | struct cred *override_cred; | ||
| 428 | struct path path; | 430 | struct path path; |
| 429 | struct inode *inode; | 431 | struct inode *inode; |
| 430 | int old_fsuid, old_fsgid; | ||
| 431 | kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */ | ||
| 432 | int res; | 432 | int res; |
| 433 | 433 | ||
| 434 | if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ | 434 | if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ |
| 435 | return -EINVAL; | 435 | return -EINVAL; |
| 436 | 436 | ||
| 437 | old_fsuid = current->fsuid; | 437 | override_cred = prepare_creds(); |
| 438 | old_fsgid = current->fsgid; | 438 | if (!override_cred) |
| 439 | return -ENOMEM; | ||
| 439 | 440 | ||
| 440 | current->fsuid = current->uid; | 441 | override_cred->fsuid = override_cred->uid; |
| 441 | current->fsgid = current->gid; | 442 | override_cred->fsgid = override_cred->gid; |
| 442 | 443 | ||
| 443 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { | 444 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
| 444 | /* | 445 | /* Clear the capabilities if we switch to a non-root user */ |
| 445 | * Clear the capabilities if we switch to a non-root user | 446 | if (override_cred->uid) |
| 446 | */ | 447 | cap_clear(override_cred->cap_effective); |
| 447 | #ifndef CONFIG_SECURITY_FILE_CAPABILITIES | ||
| 448 | /* | ||
| 449 | * FIXME: There is a race here against sys_capset. The | ||
| 450 | * capabilities can change yet we will restore the old | ||
| 451 | * value below. We should hold task_capabilities_lock, | ||
| 452 | * but we cannot because user_path_at can sleep. | ||
| 453 | */ | ||
| 454 | #endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */ | ||
| 455 | if (current->uid) | ||
| 456 | old_cap = cap_set_effective(__cap_empty_set); | ||
| 457 | else | 448 | else |
| 458 | old_cap = cap_set_effective(current->cap_permitted); | 449 | override_cred->cap_effective = |
| 450 | override_cred->cap_permitted; | ||
| 459 | } | 451 | } |
| 460 | 452 | ||
| 453 | old_cred = override_creds(override_cred); | ||
| 454 | |||
| 461 | res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); | 455 | res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); |
| 462 | if (res) | 456 | if (res) |
| 463 | goto out; | 457 | goto out; |
| @@ -494,12 +488,8 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | |||
| 494 | out_path_release: | 488 | out_path_release: |
| 495 | path_put(&path); | 489 | path_put(&path); |
| 496 | out: | 490 | out: |
| 497 | current->fsuid = old_fsuid; | 491 | revert_creds(old_cred); |
| 498 | current->fsgid = old_fsgid; | 492 | put_cred(override_cred); |
| 499 | |||
| 500 | if (!issecure(SECURE_NO_SETUID_FIXUP)) | ||
| 501 | cap_set_effective(old_cap); | ||
| 502 | |||
| 503 | return res; | 493 | return res; |
| 504 | } | 494 | } |
| 505 | 495 | ||
| @@ -792,7 +782,8 @@ static inline int __get_file_write_access(struct inode *inode, | |||
| 792 | 782 | ||
| 793 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | 783 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, |
| 794 | int flags, struct file *f, | 784 | int flags, struct file *f, |
| 795 | int (*open)(struct inode *, struct file *)) | 785 | int (*open)(struct inode *, struct file *), |
| 786 | const struct cred *cred) | ||
| 796 | { | 787 | { |
| 797 | struct inode *inode; | 788 | struct inode *inode; |
| 798 | int error; | 789 | int error; |
| @@ -816,7 +807,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
| 816 | f->f_op = fops_get(inode->i_fop); | 807 | f->f_op = fops_get(inode->i_fop); |
| 817 | file_move(f, &inode->i_sb->s_files); | 808 | file_move(f, &inode->i_sb->s_files); |
| 818 | 809 | ||
| 819 | error = security_dentry_open(f); | 810 | error = security_dentry_open(f, cred); |
| 820 | if (error) | 811 | if (error) |
| 821 | goto cleanup_all; | 812 | goto cleanup_all; |
| 822 | 813 | ||
| @@ -891,6 +882,8 @@ cleanup_file: | |||
| 891 | struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, | 882 | struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, |
| 892 | int (*open)(struct inode *, struct file *)) | 883 | int (*open)(struct inode *, struct file *)) |
| 893 | { | 884 | { |
| 885 | const struct cred *cred = current_cred(); | ||
| 886 | |||
| 894 | if (IS_ERR(nd->intent.open.file)) | 887 | if (IS_ERR(nd->intent.open.file)) |
| 895 | goto out; | 888 | goto out; |
| 896 | if (IS_ERR(dentry)) | 889 | if (IS_ERR(dentry)) |
| @@ -898,7 +891,7 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry | |||
| 898 | nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), | 891 | nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), |
| 899 | nd->intent.open.flags - 1, | 892 | nd->intent.open.flags - 1, |
| 900 | nd->intent.open.file, | 893 | nd->intent.open.file, |
| 901 | open); | 894 | open, cred); |
| 902 | out: | 895 | out: |
| 903 | return nd->intent.open.file; | 896 | return nd->intent.open.file; |
| 904 | out_err: | 897 | out_err: |
| @@ -917,6 +910,7 @@ EXPORT_SYMBOL_GPL(lookup_instantiate_filp); | |||
| 917 | */ | 910 | */ |
| 918 | struct file *nameidata_to_filp(struct nameidata *nd, int flags) | 911 | struct file *nameidata_to_filp(struct nameidata *nd, int flags) |
| 919 | { | 912 | { |
| 913 | const struct cred *cred = current_cred(); | ||
| 920 | struct file *filp; | 914 | struct file *filp; |
| 921 | 915 | ||
| 922 | /* Pick up the filp from the open intent */ | 916 | /* Pick up the filp from the open intent */ |
| @@ -924,7 +918,7 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags) | |||
| 924 | /* Has the filesystem initialised the file for us? */ | 918 | /* Has the filesystem initialised the file for us? */ |
| 925 | if (filp->f_path.dentry == NULL) | 919 | if (filp->f_path.dentry == NULL) |
| 926 | filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp, | 920 | filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp, |
| 927 | NULL); | 921 | NULL, cred); |
| 928 | else | 922 | else |
| 929 | path_put(&nd->path); | 923 | path_put(&nd->path); |
| 930 | return filp; | 924 | return filp; |
| @@ -934,7 +928,8 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags) | |||
| 934 | * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an | 928 | * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an |
| 935 | * error. | 929 | * error. |
| 936 | */ | 930 | */ |
| 937 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | 931 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, |
| 932 | const struct cred *cred) | ||
| 938 | { | 933 | { |
| 939 | int error; | 934 | int error; |
| 940 | struct file *f; | 935 | struct file *f; |
| @@ -959,7 +954,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
| 959 | return ERR_PTR(error); | 954 | return ERR_PTR(error); |
| 960 | } | 955 | } |
| 961 | 956 | ||
| 962 | return __dentry_open(dentry, mnt, flags, f, NULL); | 957 | return __dentry_open(dentry, mnt, flags, f, NULL, cred); |
| 963 | } | 958 | } |
| 964 | EXPORT_SYMBOL(dentry_open); | 959 | EXPORT_SYMBOL(dentry_open); |
| 965 | 960 | ||
