diff options
author | rodrigc <rodrigc@FreeBSD.org> | 2005-11-23 20:51:15 +0000 |
---|---|---|
committer | rodrigc <rodrigc@FreeBSD.org> | 2005-11-23 20:51:15 +0000 |
commit | dc0fe47898e981d02d4abd8f3199738c43b93096 (patch) | |
tree | d02e9c06318f0490e603e219d0d0c72ab7d0c861 /sys | |
parent | 11d4f099665bcf61936b4959251ca41db0679d67 (diff) | |
download | FreeBSD-src-dc0fe47898e981d02d4abd8f3199738c43b93096.zip FreeBSD-src-dc0fe47898e981d02d4abd8f3199738c43b93096.tar.gz |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/vfs_mount.c | 82 |
1 files changed, 46 insertions, 36 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index f3214dd..fa45ef9 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) { |