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 | ||