aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2013-08-02 00:44:31 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-08-05 10:24:11 -0400
commitbb2314b47996491bbc5add73633905c3120b6268 (patch)
treea7ce9012a84c22c5a08f89db6fb88dee093a0f88
parente305f48bc453da773a3601135a2cce40b8e62856 (diff)
fs: Allow unprivileged linkat(..., AT_EMPTY_PATH) aka flink
Every now and then someone proposes a new flink syscall, and this spawns a long discussion of whether it would be a security problem. I think that this is missing the point: flink is *already* allowed without privilege as long as /proc is mounted -- it's called AT_SYMLINK_FOLLOW. Now that O_TMPFILE is here, the ability to create a file with O_TMPFILE, write it, and link it in is very convenient. The only problem is that it requires that /proc be mounted so that you can do: linkat(AT_FDCWD, "/proc/self/fd/<tmpfd>", dfd, path, AT_SYMLINK_NOFOLLOW) This sucks -- it's much nicer to do: linkat(tmpfd, "", dfd, path, AT_EMPTY_PATH) Let's allow it. If this turns out to be excessively scary, it we could instead require that the inode in question be I_LINKABLE, but this seems pointless given the /proc situation Signed-off-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c10
1 files changed, 3 insertions, 7 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 8b61d103a8a7..89a612e392eb 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3671,15 +3671,11 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
3671 if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) 3671 if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
3672 return -EINVAL; 3672 return -EINVAL;
3673 /* 3673 /*
3674 * To use null names we require CAP_DAC_READ_SEARCH 3674 * Using empty names is equivalent to using AT_SYMLINK_FOLLOW
3675 * This ensures that not everyone will be able to create 3675 * on /proc/self/fd/<fd>.
3676 * handlink using the passed filedescriptor.
3677 */ 3676 */
3678 if (flags & AT_EMPTY_PATH) { 3677 if (flags & AT_EMPTY_PATH)
3679 if (!capable(CAP_DAC_READ_SEARCH))
3680 return -ENOENT;
3681 how = LOOKUP_EMPTY; 3678 how = LOOKUP_EMPTY;
3682 }
3683 3679
3684 if (flags & AT_SYMLINK_FOLLOW) 3680 if (flags & AT_SYMLINK_FOLLOW)
3685 how |= LOOKUP_FOLLOW; 3681 how |= LOOKUP_FOLLOW;