In nmount() and vfs_donmount(), do not strcmp() the options in the iovec

directly.  We need to copyin() the strings in the iovec before
we can strcmp() them.  Also, when we want to send the errmsg back
to userspace, we need to copyout()/copystr() the string.

Add a small helper function vfs_getopt_pos() which takes in the
name of an option, and returns the array index of the name in the iovec,
or -1 if not found.  This allows us to locate an option in
the iovec without actually manipulating the iovec members. directly via
strcmp().

Noticed by:	kris on sparc64
This commit is contained in:
rodrigc 2005-11-23 20:51:15 +00:00
parent 11d4f09966
commit dc0fe47898

View File

@ -83,6 +83,7 @@ static int vfs_donmount(struct thread *td, int fsflags,
struct uio *fsoptions);
static void free_mntarg(struct mntarg *ma);
static void vfs_mount_destroy(struct mount *, struct thread *);
static int vfs_getopt_pos(struct vfsoptlist *opts, const char *name);
static int usermount = 0;
SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0,
@ -365,7 +366,6 @@ nmount(td, uap)
unsigned int i;
int error;
u_int iovcnt;
const char *name;
/* Kick out MNT_ROOTFS early as it is legal internally */
if (uap->flags & MNT_ROOTFS)
@ -392,16 +392,6 @@ nmount(td, uap)
}
error = vfs_donmount(td, uap->flags, auio);
/* copyout the errmsg */
for (i = 0; error != 0 && i < iovcnt; i += 2) {
name = (const char *)auio->uio_iov[i].iov_base;
if (strcmp(name, "errmsg") == 0) {
copyout(auio->uio_iov[i + 1].iov_base,
uap->iovp[i + 1].iov_base, uap->iovp[i + 1].iov_len);
break;
}
}
free(auio, M_IOV);
return (error);
}
@ -476,21 +466,21 @@ static int
vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions)
{
struct vfsoptlist *optlist;
struct iovec *iov_errmsg;
char *fstype, *fspath;
int error, fstypelen, fspathlen, i;
char *fstype, *fspath, *errmsg;
int error, fstypelen, fspathlen, errmsg_len, errmsg_pos;
iov_errmsg = NULL;
for (i = 0; i < fsoptions->uio_iovcnt; i += 2) {
if (strcmp((char *)fsoptions->uio_iov[i].iov_base, "errmsg") == 0)
iov_errmsg = &fsoptions->uio_iov[i + 1];
}
errmsg_len = 0;
errmsg_pos = -1;
error = vfs_buildopts(fsoptions, &optlist);
if (error)
return (error);
if (vfs_getopt(optlist, "errmsg", (void **)&errmsg, &errmsg_len) == 0)
errmsg_pos = vfs_getopt_pos(optlist, "errmsg");
else
errmsg_len = 0;
/*
* We need these two options before the others,
* and they are mandatory for any filesystem.
@ -500,18 +490,16 @@ vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions)
error = vfs_getopt(optlist, "fstype", (void **)&fstype, &fstypelen);
if (error || fstype[fstypelen - 1] != '\0') {
error = EINVAL;
if (iov_errmsg != NULL)
strncpy((char *)iov_errmsg->iov_base, "Invalid fstype",
iov_errmsg->iov_len);
if (errmsg != NULL)
strncpy(errmsg, "Invalid fstype", errmsg_len);
goto bail;
}
fspathlen = 0;
error = vfs_getopt(optlist, "fspath", (void **)&fspath, &fspathlen);
if (error || fspath[fspathlen - 1] != '\0') {
error = EINVAL;
if (iov_errmsg != NULL)
strncpy((char *)iov_errmsg->iov_base, "Invalid fspath",
iov_errmsg->iov_len);
if (errmsg != NULL)
strncpy(errmsg, "Invalid fspath", errmsg_len);
goto bail;
}
@ -580,17 +568,21 @@ vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions)
error = vfs_domount(td, fstype, fspath, fsflags, optlist);
mtx_unlock(&Giant);
bail:
if (error != 0 && iov_errmsg != NULL) {
/* Save the errmsg so we can return it to userspace. */
char *errmsg;
int len, ret;
ret = vfs_getopt(optlist, "errmsg", (void **)&errmsg, &len);
if (ret == 0 && len > 0)
strncpy((char *)iov_errmsg->iov_base, errmsg,
iov_errmsg->iov_len);
/* copyout the errmsg */
if (errmsg_pos != -1 && ((2 * errmsg_pos + 1) < fsoptions->uio_iovcnt)
&& errmsg_len > 0 && errmsg != NULL) {
if (fsoptions->uio_segflg == UIO_SYSSPACE) {
strncpy(fsoptions->uio_iov[2 * errmsg_pos + 1].iov_base,
errmsg,
fsoptions->uio_iov[2 * errmsg_pos + 1].iov_len);
} else {
copystr(errmsg,
fsoptions->uio_iov[2 * errmsg_pos + 1].iov_base,
fsoptions->uio_iov[2 * errmsg_pos + 1].iov_len,
NULL);
}
}
if (error != 0)
vfs_freeopts(optlist);
return (error);
@ -1543,6 +1535,24 @@ vfs_getopt(opts, name, buf, len)
return (ENOENT);
}
static int
vfs_getopt_pos(struct vfsoptlist *opts, const char *name)
{
struct vfsopt *opt;
int i;
if (opts == NULL)
return (-1);
i = 0;
TAILQ_FOREACH(opt, opts, link) {
if (strcmp(name, opt->name) == 0)
return (i);
++i;
}
return (-1);
}
char *
vfs_getopts(struct vfsoptlist *opts, const char *name, int *error)
{