1 /* $NetBSD: vfs_syscalls_30.c,v 1.36 2014/10/20 11:58:01 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_30.c,v 1.36 2014/10/20 11:58:01 christos Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/namei.h> 37 #include <sys/filedesc.h> 38 #include <sys/kernel.h> 39 #include <sys/file.h> 40 #include <sys/stat.h> 41 #include <sys/socketvar.h> 42 #include <sys/vnode.h> 43 #include <sys/mount.h> 44 #include <sys/proc.h> 45 #include <sys/uio.h> 46 #include <sys/dirent.h> 47 #include <sys/malloc.h> 48 #include <sys/kauth.h> 49 #include <sys/vfs_syscalls.h> 50 51 #include <sys/syscallargs.h> 52 53 #include <compat/common/compat_util.h> 54 #include <compat/sys/stat.h> 55 #include <compat/sys/dirent.h> 56 #include <compat/sys/mount.h> 57 58 static void cvtstat(struct stat13 *, const struct stat *); 59 60 /* 61 * Convert from a new to an old stat structure. 62 */ 63 static void 64 cvtstat(struct stat13 *ost, const struct stat *st) 65 { 66 67 ost->st_dev = st->st_dev; 68 ost->st_ino = (uint32_t)st->st_ino; 69 ost->st_mode = st->st_mode; 70 ost->st_nlink = st->st_nlink; 71 ost->st_uid = st->st_uid; 72 ost->st_gid = st->st_gid; 73 ost->st_rdev = st->st_rdev; 74 timespec_to_timespec50(&st->st_atimespec, &ost->st_atimespec); 75 timespec_to_timespec50(&st->st_mtimespec, &ost->st_mtimespec); 76 timespec_to_timespec50(&st->st_ctimespec, &ost->st_ctimespec); 77 timespec_to_timespec50(&st->st_birthtimespec, &ost->st_birthtimespec); 78 ost->st_size = st->st_size; 79 ost->st_blocks = st->st_blocks; 80 ost->st_blksize = st->st_blksize; 81 ost->st_flags = st->st_flags; 82 ost->st_gen = st->st_gen; 83 } 84 85 /* 86 * Get file status; this version follows links. 87 */ 88 /* ARGSUSED */ 89 int 90 compat_30_sys___stat13(struct lwp *l, const struct compat_30_sys___stat13_args *uap, register_t *retval) 91 { 92 /* { 93 syscallarg(const char *) path; 94 syscallarg(struct stat13 *) ub; 95 } */ 96 struct stat sb; 97 struct stat13 osb; 98 int error; 99 100 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 101 if (error) 102 return error; 103 cvtstat(&osb, &sb); 104 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 105 return error; 106 } 107 108 109 /* 110 * Get file status; this version does not follow links. 111 */ 112 /* ARGSUSED */ 113 int 114 compat_30_sys___lstat13(struct lwp *l, const struct compat_30_sys___lstat13_args *uap, register_t *retval) 115 { 116 /* { 117 syscallarg(const char *) path; 118 syscallarg(struct stat13 *) ub; 119 } */ 120 struct stat sb; 121 struct stat13 osb; 122 int error; 123 124 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 125 if (error) 126 return error; 127 cvtstat(&osb, &sb); 128 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 129 return error; 130 } 131 132 /* ARGSUSED */ 133 int 134 compat_30_sys_fhstat(struct lwp *l, const struct compat_30_sys_fhstat_args *uap, register_t *retval) 135 { 136 /* { 137 syscallarg(const struct compat_30_fhandle *) fhp; 138 syscallarg(struct stat13 *) sb; 139 } */ 140 struct stat sb; 141 struct stat13 osb; 142 int error; 143 struct compat_30_fhandle fh; 144 struct mount *mp; 145 struct vnode *vp; 146 147 /* 148 * Must be super user 149 */ 150 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE, 151 0, NULL, NULL, NULL))) 152 return (error); 153 154 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fh))) != 0) 155 return (error); 156 157 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 158 return (ESTALE); 159 if (mp->mnt_op->vfs_fhtovp == NULL) 160 return EOPNOTSUPP; 161 if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) 162 return (error); 163 error = vn_stat(vp, &sb); 164 vput(vp); 165 if (error) 166 return (error); 167 cvtstat(&osb, &sb); 168 error = copyout(&osb, SCARG(uap, sb), sizeof(sb)); 169 return (error); 170 } 171 172 /* 173 * Return status information about a file descriptor. 174 */ 175 /* ARGSUSED */ 176 int 177 compat_30_sys___fstat13(struct lwp *l, const struct compat_30_sys___fstat13_args *uap, register_t *retval) 178 { 179 /* { 180 syscallarg(int) fd; 181 syscallarg(struct stat13 *) sb; 182 } */ 183 struct stat sb; 184 struct stat13 osb; 185 int error; 186 187 error = do_sys_fstat(SCARG(uap, fd), &sb); 188 if (error) 189 return error; 190 cvtstat(&osb, &sb); 191 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 192 return error; 193 } 194 195 /* 196 * Read a block of directory entries in a file system independent format. 197 */ 198 int 199 compat_30_sys_getdents(struct lwp *l, const struct compat_30_sys_getdents_args *uap, register_t *retval) 200 { 201 /* { 202 syscallarg(int) fd; 203 syscallarg(char *) buf; 204 syscallarg(size_t) count; 205 } */ 206 struct dirent *bdp; 207 struct vnode *vp; 208 char *inp, *tbuf; /* BSD-format */ 209 int len, reclen; /* BSD-format */ 210 char *outp; /* NetBSD-3.0-format */ 211 int resid; 212 struct file *fp; 213 struct uio auio; 214 struct iovec aiov; 215 struct dirent12 idb; 216 off_t off; /* true file offset */ 217 int buflen, error, eofflag; 218 off_t *cookiebuf = NULL, *cookie; 219 int ncookies; 220 221 /* fd_getvnode() will use the descriptor for us */ 222 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 223 return error; 224 225 if ((fp->f_flag & FREAD) == 0) { 226 error = EBADF; 227 goto out1; 228 } 229 230 vp = fp->f_vnode; 231 if (vp->v_type != VDIR) { 232 error = EINVAL; 233 goto out1; 234 } 235 236 buflen = min(MAXBSIZE, SCARG(uap, count)); 237 tbuf = malloc(buflen, M_TEMP, M_WAITOK); 238 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 239 off = fp->f_offset; 240 again: 241 aiov.iov_base = tbuf; 242 aiov.iov_len = buflen; 243 auio.uio_iov = &aiov; 244 auio.uio_iovcnt = 1; 245 auio.uio_rw = UIO_READ; 246 auio.uio_resid = buflen; 247 auio.uio_offset = off; 248 UIO_SETUP_SYSSPACE(&auio); 249 /* 250 * First we read into the malloc'ed buffer, then 251 * we massage it into user space, one record at a time. 252 */ 253 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 254 &ncookies); 255 if (error) 256 goto out; 257 258 inp = tbuf; 259 outp = SCARG(uap, buf); 260 resid = SCARG(uap, count); 261 if ((len = buflen - auio.uio_resid) == 0) 262 goto eof; 263 264 for (cookie = cookiebuf; len > 0; len -= reclen) { 265 bdp = (struct dirent *)inp; 266 reclen = bdp->d_reclen; 267 if (reclen & _DIRENT_ALIGN(bdp)) 268 panic("netbsd30_getdents: bad reclen %d", reclen); 269 if (cookie) 270 off = *cookie++; /* each entry points to the next */ 271 else 272 off += reclen; 273 if ((off >> 32) != 0) { 274 compat_offseterr(vp, "netbsd30_getdents"); 275 error = EINVAL; 276 goto out; 277 } 278 if (bdp->d_namlen >= sizeof(idb.d_name)) 279 idb.d_namlen = sizeof(idb.d_name) - 1; 280 else 281 idb.d_namlen = bdp->d_namlen; 282 idb.d_reclen = _DIRENT_SIZE(&idb); 283 if (reclen > len || resid < idb.d_reclen) { 284 /* entry too big for buffer, so just stop */ 285 outp++; 286 break; 287 } 288 /* 289 * Massage in place to make a NetBSD-3.0-shaped dirent 290 * (otherwise we have to worry about touching user memory 291 * outside of the copyout() call). 292 */ 293 idb.d_fileno = (u_int32_t)bdp->d_fileno; 294 idb.d_type = bdp->d_type; 295 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen); 296 memset(idb.d_name + idb.d_namlen, 0, 297 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen); 298 if ((error = copyout(&idb, outp, idb.d_reclen)) != 0) 299 goto out; 300 /* advance past this real entry */ 301 inp += reclen; 302 /* advance output past NetBSD-3.0-shaped entry */ 303 outp += idb.d_reclen; 304 resid -= idb.d_reclen; 305 } 306 307 /* if we squished out the whole block, try again */ 308 if (outp == SCARG(uap, buf)) { 309 if (cookiebuf) 310 free(cookiebuf, M_TEMP); 311 cookiebuf = NULL; 312 goto again; 313 } 314 fp->f_offset = off; /* update the vnode offset */ 315 316 eof: 317 *retval = SCARG(uap, count) - resid; 318 out: 319 VOP_UNLOCK(vp); 320 if (cookiebuf) 321 free(cookiebuf, M_TEMP); 322 free(tbuf, M_TEMP); 323 out1: 324 fd_putfile(SCARG(uap, fd)); 325 return error; 326 } 327 328 /* 329 * Get file handle system call 330 */ 331 int 332 compat_30_sys_getfh(struct lwp *l, const struct compat_30_sys_getfh_args *uap, register_t *retval) 333 { 334 /* { 335 syscallarg(char *) fname; 336 syscallarg(struct compat_30_fhandle *) fhp; 337 } */ 338 struct vnode *vp; 339 struct compat_30_fhandle fh; 340 int error; 341 struct pathbuf *pb; 342 struct nameidata nd; 343 size_t sz; 344 345 /* 346 * Must be super user 347 */ 348 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE, 349 0, NULL, NULL, NULL); 350 if (error) 351 return (error); 352 353 error = pathbuf_copyin(SCARG(uap, fname), &pb); 354 if (error) { 355 return error; 356 } 357 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb); 358 error = namei(&nd); 359 pathbuf_destroy(pb); 360 if (error) 361 return error; 362 vp = nd.ni_vp; 363 364 sz = sizeof(struct compat_30_fhandle); 365 error = vfs_composefh(vp, (void *)&fh, &sz); 366 vput(vp); 367 if (sz != FHANDLE_SIZE_COMPAT) { 368 error = EINVAL; 369 } 370 if (error) 371 return (error); 372 error = copyout(&fh, SCARG(uap, fhp), sizeof(struct compat_30_fhandle)); 373 return (error); 374 } 375 376 /* 377 * Open a file given a file handle. 378 * 379 * Check permissions, allocate an open file structure, 380 * and call the device open routine if any. 381 */ 382 int 383 compat_30_sys_fhopen(struct lwp *l, const struct compat_30_sys_fhopen_args *uap, register_t *retval) 384 { 385 /* { 386 syscallarg(const fhandle_t *) fhp; 387 syscallarg(int) flags; 388 } */ 389 390 return dofhopen(l, SCARG(uap, fhp), FHANDLE_SIZE_COMPAT, 391 SCARG(uap, flags), retval); 392 } 393 394 /* ARGSUSED */ 395 int 396 compat_30_sys___fhstat30(struct lwp *l, const struct compat_30_sys___fhstat30_args *uap_30, register_t *retval) 397 { 398 /* { 399 syscallarg(const fhandle_t *) fhp; 400 syscallarg(struct stat30 *) sb; 401 } */ 402 struct stat sb; 403 struct stat13 osb; 404 int error; 405 406 error = do_fhstat(l, SCARG(uap_30, fhp), FHANDLE_SIZE_COMPAT, &sb); 407 if (error) 408 return error; 409 cvtstat(&osb, &sb); 410 error = copyout(&osb, SCARG(uap_30, sb), sizeof (osb)); 411 return error; 412 } 413 414 /* ARGSUSED */ 415 int 416 compat_30_sys_fhstatvfs1(struct lwp *l, const struct compat_30_sys_fhstatvfs1_args *uap_30, register_t *retval) 417 { 418 /* { 419 syscallarg(const fhandle_t *) fhp; 420 syscallarg(struct statvfs *) buf; 421 syscallarg(int) flags; 422 } */ 423 struct sys___fhstatvfs140_args uap; 424 425 SCARG(&uap, fhp) = SCARG(uap_30, fhp); 426 SCARG(&uap, fh_size) = FHANDLE_SIZE_COMPAT; 427 SCARG(&uap, buf) = SCARG(uap_30, buf); 428 SCARG(&uap, flags) = SCARG(uap_30, flags); 429 430 return sys___fhstatvfs140(l, &uap, retval); 431 } 432