1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. 31 * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. 32 * Copyright 2026 Oxide Computer Company 33 */ 34 /* 35 * Portions of this source code were derived from Berkeley 4.3 BSD 36 * under license from the Regents of the University of California. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/isa_defs.h> 41 #include <sys/types.h> 42 #include <sys/sysmacros.h> 43 #include <sys/user.h> 44 #include <sys/systm.h> 45 #include <sys/errno.h> 46 #include <sys/fcntl.h> 47 #include <sys/stat.h> 48 #include <sys/vnode.h> 49 #include <sys/vfs.h> 50 #include <sys/file.h> 51 #include <sys/mode.h> 52 #include <sys/model.h> 53 #include <sys/uio.h> 54 #include <sys/debug.h> 55 #include <c2/audit.h> 56 57 /* 58 * Common code for openat(). Check permissions, allocate an open 59 * file structure, and call the device open routine (if any). 60 */ 61 62 static int 63 copen(int startfd, char *fname, int filemode, int createmode, uio_seg_t seg) 64 { 65 struct pathname pn; 66 vnode_t *vp, *sdvp; 67 file_t *fp, *startfp; 68 enum vtype type; 69 int error; 70 int fd, dupfd; 71 vnode_t *startvp; 72 proc_t *p = curproc; 73 char *open_filename = fname; 74 uint32_t auditing = AU_AUDITING(); 75 char startchar; 76 77 if (filemode & (FSEARCH|FEXEC)) { 78 /* 79 * Must be one or the other and neither FREAD nor FWRITE 80 * Must not be any of FAPPEND FCREAT FTRUNC FXATTR FXATTRDIROPEN 81 * XXX: Should these just be silently ignored? 82 */ 83 if ((filemode & (FREAD|FWRITE)) || 84 (filemode & (FSEARCH|FEXEC)) == (FSEARCH|FEXEC) || 85 (filemode & (FAPPEND|FCREAT|FTRUNC|FXATTR|FXATTRDIROPEN))) 86 return (set_errno(EINVAL)); 87 } 88 89 if (startfd == AT_FDCWD) { 90 /* 91 * Regular open() 92 */ 93 startvp = NULL; 94 } else { 95 /* 96 * We're here via openat() 97 */ 98 if (seg == UIO_SYSSPACE) 99 startchar = *fname; 100 else if (copyin(fname, &startchar, sizeof (char))) 101 return (set_errno(EFAULT)); 102 103 /* 104 * if startchar is / then startfd is ignored 105 */ 106 if (startchar == '/') 107 startvp = NULL; 108 else { 109 if ((startfp = getf(startfd)) == NULL) 110 return (set_errno(EBADF)); 111 startvp = startfp->f_vnode; 112 VN_HOLD(startvp); 113 releasef(startfd); 114 } 115 } 116 117 /* 118 * Handle __openattrdirat() requests 119 */ 120 if (filemode & FXATTRDIROPEN) { 121 if (auditing && startvp != NULL) 122 audit_setfsat_path(1); 123 error = lookupnameat(fname, seg, FOLLOW, NULLVPP, &vp, startvp); 124 if (startvp != NULL) 125 VN_RELE(startvp); 126 if (error != 0) 127 return (set_errno(error)); 128 129 startvp = vp; 130 } 131 132 /* 133 * Do we need to go into extended attribute space? 134 */ 135 if (filemode & FXATTR) { 136 if (startfd == AT_FDCWD) { 137 if (seg == UIO_SYSSPACE) 138 startchar = *fname; 139 else if (copyin(fname, &startchar, sizeof (char))) 140 return (set_errno(EFAULT)); 141 142 /* 143 * If startchar == '/' then no extended attributes 144 * are looked up. 145 */ 146 if (startchar == '/') { 147 startvp = NULL; 148 } else { 149 mutex_enter(&p->p_lock); 150 startvp = PTOU(p)->u_cdir; 151 VN_HOLD(startvp); 152 mutex_exit(&p->p_lock); 153 } 154 } 155 156 /* 157 * Make sure we have a valid extended attribute request. 158 * We must either have a real fd or AT_FDCWD and a relative 159 * pathname. 160 */ 161 if (startvp == NULL) { 162 goto noxattr; 163 } 164 } 165 166 if (filemode & (FXATTR|FXATTRDIROPEN)) { 167 vattr_t vattr; 168 169 if (error = pn_get(fname, seg, &pn)) { 170 goto out; 171 } 172 173 /* 174 * In order to access hidden attribute directory the 175 * user must be able to stat() the file 176 */ 177 vattr.va_mask = AT_ALL; 178 if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) { 179 pn_free(&pn); 180 goto out; 181 } 182 183 if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 || 184 vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { 185 error = VOP_LOOKUP(startvp, "", &sdvp, &pn, 186 (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR : 187 LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(), 188 NULL, NULL, NULL); 189 } else { 190 error = EINVAL; 191 } 192 193 /* 194 * For __openattrdirat() use "." as filename to open 195 * as part of vn_openat() 196 */ 197 if (error == 0 && (filemode & FXATTRDIROPEN)) { 198 open_filename = "."; 199 seg = UIO_SYSSPACE; 200 } 201 202 pn_free(&pn); 203 if (error != 0) 204 goto out; 205 206 VN_RELE(startvp); 207 startvp = sdvp; 208 } 209 210 noxattr: 211 if ((filemode & (FREAD|FWRITE|FSEARCH|FEXEC|FXATTRDIROPEN)) != 0) { 212 if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) 213 filemode &= ~FNDELAY; 214 error = falloc((vnode_t *)NULL, filemode, &fp, &fd); 215 if (error == 0) { 216 if (auditing && startvp != NULL) 217 audit_setfsat_path(1); 218 /* 219 * Last arg is a don't-care term if 220 * !(filemode & FCREAT). 221 */ 222 error = vn_openat(open_filename, seg, filemode, 223 (int)(createmode & MODEMASK), 224 &vp, CRCREAT, PTOU(curproc)->u_cmask, 225 startvp, fd); 226 227 if (startvp != NULL) 228 VN_RELE(startvp); 229 if (error == 0) { 230 if ((vp->v_flag & VDUP) == 0) { 231 fp->f_vnode = vp; 232 mutex_exit(&fp->f_tlock); 233 /* 234 * We must now fill in the slot 235 * falloc reserved. 236 */ 237 setf(fd, fp); 238 if ((filemode & FCLOEXEC) != 0) { 239 f_setfd_or(fd, FD_CLOEXEC); 240 } 241 242 if ((filemode & FCLOFORK) != 0) { 243 f_setfd_or(fd, FD_CLOFORK); 244 } 245 return (fd); 246 } else { 247 /* 248 * Special handling for /dev/fd. 249 * Give up the file pointer 250 * and dup the indicated file descriptor 251 * (in v_rdev). This is ugly, but I've 252 * seen worse. 253 */ 254 unfalloc(fp); 255 dupfd = getminor(vp->v_rdev); 256 type = vp->v_type; 257 mutex_enter(&vp->v_lock); 258 vp->v_flag &= ~VDUP; 259 mutex_exit(&vp->v_lock); 260 VN_RELE(vp); 261 if (type != VCHR) 262 return (set_errno(EINVAL)); 263 if ((fp = getf(dupfd)) == NULL) { 264 setf(fd, NULL); 265 return (set_errno(EBADF)); 266 } 267 mutex_enter(&fp->f_tlock); 268 fp->f_count++; 269 mutex_exit(&fp->f_tlock); 270 setf(fd, fp); 271 if ((filemode & FCLOEXEC) != 0) { 272 f_setfd_or(fd, FD_CLOEXEC); 273 } 274 275 if ((filemode & FCLOFORK) != 0) { 276 f_setfd_or(fd, FD_CLOFORK); 277 } 278 releasef(dupfd); 279 } 280 return (fd); 281 } else { 282 setf(fd, NULL); 283 unfalloc(fp); 284 return (set_errno(error)); 285 } 286 } 287 } else { 288 error = EINVAL; 289 } 290 out: 291 if (startvp != NULL) 292 VN_RELE(startvp); 293 return (set_errno(error)); 294 } 295 296 #define OPENMODE32(fmode) (((fmode) & (FSEARCH | FEXEC))? \ 297 (fmode) : (fmode) - FOPEN) 298 #define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX) 299 #ifdef _LP64 300 #define OPENMODE(fmode) OPENMODE64(fmode) 301 #else 302 #define OPENMODE(fmode) OPENMODE32(fmode) 303 #endif 304 305 /* 306 * Kernel-callable open of a kernel-resident path, used to apply spawn(2) 307 * file actions in a spawned child. 308 * 309 * copen() reports failure by returning the error number from set_errno(), 310 * which is indistinguishable by value from a valid file descriptor. We 311 * convert to the convention expected by an in-kernel caller - a return of 312 * -1 with the error left in lwp_errno, and the file descriptor otherwise. 313 */ 314 int 315 kopenat(int startfd, char *path, int fmode, int cmode, model_t model) 316 { 317 klwp_t *lwp = ttolwp(curthread); 318 int fd; 319 320 if (model == DATAMODEL_ILP32) 321 fmode = OPENMODE32(fmode); 322 else 323 fmode = OPENMODE64(fmode); 324 325 lwp->lwp_errno = 0; 326 fd = copen(startfd, path, fmode, cmode, UIO_SYSSPACE); 327 if (lwp->lwp_errno != 0) 328 return (-1); 329 330 return (fd); 331 } 332 333 /* 334 * Open a file. 335 */ 336 int 337 openat(int fd, char *path, int fmode, int cmode) 338 { 339 return (copen(fd, path, OPENMODE(fmode), cmode, UIO_USERSPACE)); 340 } 341 342 int 343 open(char *path, int fmode, int cmode) 344 { 345 return (openat(AT_FDCWD, path, fmode, cmode)); 346 } 347 348 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 349 /* 350 * Open for large files in 32-bit environment. Sets the FOFFMAX flag. 351 */ 352 int 353 openat64(int fd, char *path, int fmode, int cmode) 354 { 355 return (copen(fd, path, OPENMODE64(fmode), cmode, UIO_USERSPACE)); 356 } 357 358 int 359 open64(char *path, int fmode, int cmode) 360 { 361 return (openat64(AT_FDCWD, path, fmode, cmode)); 362 } 363 364 #endif /* _ILP32 || _SYSCALL32_IMPL */ 365 366 #ifdef _SYSCALL32_IMPL 367 /* 368 * Open for 32-bit compatibility on 64-bit kernel 369 */ 370 int 371 openat32(int fd, char *path, int fmode, int cmode) 372 { 373 return (copen(fd, path, OPENMODE32(fmode), cmode, UIO_USERSPACE)); 374 } 375 376 int 377 open32(char *path, int fmode, int cmode) 378 { 379 return (openat32(AT_FDCWD, path, fmode, cmode)); 380 } 381 382 #endif /* _SYSCALL32_IMPL */ 383