summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/open.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/fs/open.c b/fs/open.c
index 719b320ede52..0ea3cd1a1250 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -345,21 +345,14 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
* We do this by temporarily clearing all FS-related capabilities and
* switching the fsuid/fsgid around to the real ones.
*/
-long do_faccessat(int dfd, const char __user *filename, int mode)
+static const struct cred *access_override_creds(void)
{
const struct cred *old_cred;
struct cred *override_cred;
- struct path path;
- struct inode *inode;
- int res;
- unsigned int lookup_flags = LOOKUP_FOLLOW;
-
- if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
- return -EINVAL;
override_cred = prepare_creds();
if (!override_cred)
- return -ENOMEM;
+ return NULL;
override_cred->fsuid = override_cred->uid;
override_cred->fsgid = override_cred->gid;
@@ -394,6 +387,28 @@ long do_faccessat(int dfd, const char __user *filename, int mode)
override_cred->non_rcu = 1;
old_cred = override_creds(override_cred);
+
+ /* override_cred() gets its own ref */
+ put_cred(override_cred);
+
+ return old_cred;
+}
+
+long do_faccessat(int dfd, const char __user *filename, int mode)
+{
+ struct path path;
+ struct inode *inode;
+ int res;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
+ const struct cred *old_cred;
+
+ if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
+ return -EINVAL;
+
+ old_cred = access_override_creds();
+ if (!old_cred)
+ return -ENOMEM;
+
retry:
res = user_path_at(dfd, filename, lookup_flags, &path);
if (res)
@@ -436,7 +451,6 @@ out_path_release:
}
out:
revert_creds(old_cred);
- put_cred(override_cred);
return res;
}