VFS: clean up and simplify getname_flags()

This removes a number of silly games around strncpy_from_user() in
do_getname(), and removes that helper function entirely.  We instead
make getname_flags() just use strncpy_from_user() properly directly.

Removing the wrapper function simplifies things noticeably, mostly
because we no longer play the unnecessary games with segments (x86
strncpy_from_user() no longer needs the hack), but also because the
empty path handling is just much more obvious.  The return value of
"strncpy_to_user()" is much more obvious than checking an odd error
return case from do_getname().

[ non-x86 architectures were notified of this change several weeks ago,
  since it is possible that they have copied the old broken x86
  strncpy_from_user. But nobody reacted, so .. See

    http://www.spinics.net/lists/linux-arch/msg17313.html

  for details ]

Cc: linux-arch@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2012-04-28 14:38:32 -07:00
parent 0749708352
commit 3f9f0aa687
1 changed files with 24 additions and 34 deletions

View File

@ -116,49 +116,39 @@
* POSIX.1 2.4: an empty pathname is invalid (ENOENT).
* PATH_MAX includes the nul terminator --RR.
*/
static int do_getname(const char __user *filename, char *page)
{
int retval;
unsigned long len = PATH_MAX;
if (!segment_eq(get_fs(), KERNEL_DS)) {
if ((unsigned long) filename >= TASK_SIZE)
return -EFAULT;
if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
len = TASK_SIZE - (unsigned long) filename;
}
retval = strncpy_from_user(page, filename, len);
if (retval > 0) {
if (retval < len)
return 0;
return -ENAMETOOLONG;
} else if (!retval)
retval = -ENOENT;
return retval;
}
static char *getname_flags(const char __user *filename, int flags, int *empty)
{
char *result = __getname();
int retval;
char *result = __getname(), *err;
int len;
if (!result)
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
retval = do_getname(filename, result);
if (retval < 0) {
if (retval == -ENOENT && empty)
len = strncpy_from_user(result, filename, PATH_MAX);
err = ERR_PTR(len);
if (unlikely(len < 0))
goto error;
/* The empty path is special. */
if (unlikely(!len)) {
if (empty)
*empty = 1;
if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
__putname(result);
return ERR_PTR(retval);
}
err = ERR_PTR(-ENOENT);
if (!(flags & LOOKUP_EMPTY))
goto error;
}
err = ERR_PTR(-ENAMETOOLONG);
if (likely(len < PATH_MAX)) {
audit_getname(result);
return result;
}
error:
__putname(result);
return err;
}
char *getname(const char __user * filename)
{
return getname_flags(filename, 0, NULL);