From dc0fe47898e981d02d4abd8f3199738c43b93096 Mon Sep 17 00:00:00 2001 From: rodrigc Date: Wed, 23 Nov 2005 20:51:15 +0000 Subject: [PATCH] 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 --- sys/kern/vfs_mount.c | 82 +++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index f3214dd4ee72..fa45ef9f10b2 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -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) {