Update vn_set_pwd() to allow user|kernal address for filename

During module init spl_setup()->The vn_set_pwd("/") was failing
with -EFAULT because user_path_dir() and __user_walk() both
expect 'filename' to be a user space address and it's not in
this case.  To handle this the data segment size is increased
to to ensure strncpy_from_user() does not fail with -EFAULT.

Additionally, I've added a printk() warning to catch this and
log it to the console if it ever reoccurs.  I thought everything
was working properly here because there consequences of this
failing are subtle and usually non-critical.
This commit is contained in:
Brian Behlendorf 2010-04-22 12:48:40 -07:00
parent ef6c136884
commit 82a358d9c0
2 changed files with 20 additions and 5 deletions

View File

@ -444,12 +444,16 @@ spl_fini(void)
void void
spl_setup(void) spl_setup(void)
{ {
int rc;
/* /*
* At module load time the pwd is set to '/' on a Solaris system. * At module load time the pwd is set to '/' on a Solaris system.
* On a Linux system will be set to whatever directory the caller * On a Linux system will be set to whatever directory the caller
* was in when executing insmod/modprobe. * was in when executing insmod/modprobe.
*/ */
vn_set_pwd("/"); rc = vn_set_pwd("/");
if (rc)
printk("SPL: Warning unable to set pwd to '/': %d\n", rc);
} }
EXPORT_SYMBOL(spl_setup); EXPORT_SYMBOL(spl_setup);

View File

@ -647,9 +647,22 @@ vn_set_pwd(const char *filename)
{ {
#ifdef HAVE_2ARGS_SET_FS_PWD #ifdef HAVE_2ARGS_SET_FS_PWD
struct path path; struct path path;
#else
struct nameidata nd;
#endif /* HAVE_2ARGS_SET_FS_PWD */
mm_segment_t saved_fs;
int rc; int rc;
ENTRY; ENTRY;
/*
* user_path_dir() and __user_walk() both expect 'filename' to be
* a user space address so we must briefly increase the data segment
* size to ensure strncpy_from_user() does not fail with -EFAULT.
*/
saved_fs = get_fs();
set_fs(get_ds());
#ifdef HAVE_2ARGS_SET_FS_PWD
rc = user_path_dir(filename, &path); rc = user_path_dir(filename, &path);
if (rc) if (rc)
GOTO(out, rc); GOTO(out, rc);
@ -663,10 +676,6 @@ vn_set_pwd(const char *filename)
dput_and_out: dput_and_out:
path_put(&path); path_put(&path);
#else #else
struct nameidata nd;
int rc;
ENTRY;
rc = __user_walk(filename, rc = __user_walk(filename,
LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd); LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
if (rc) if (rc)
@ -682,6 +691,8 @@ dput_and_out:
vn_path_release(&nd); vn_path_release(&nd);
#endif /* HAVE_2ARGS_SET_FS_PWD */ #endif /* HAVE_2ARGS_SET_FS_PWD */
out: out:
set_fs(saved_fs);
RETURN(-rc); RETURN(-rc);
} /* vn_set_pwd() */ } /* vn_set_pwd() */
EXPORT_SYMBOL(vn_set_pwd); EXPORT_SYMBOL(vn_set_pwd);