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 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/isa_defs.h> 36 #include <sys/types.h> 37 #include <sys/sysmacros.h> 38 #include <sys/user.h> 39 #include <sys/systm.h> 40 #include <sys/errno.h> 41 #include <sys/fcntl.h> 42 #include <sys/stat.h> 43 #include <sys/vnode.h> 44 #include <sys/vfs.h> 45 #include <sys/file.h> 46 #include <sys/mode.h> 47 #include <sys/uio.h> 48 #include <sys/debug.h> 49 #include <c2/audit.h> 50 51 /* 52 * Common code for openat(). Check permissions, allocate an open 53 * file structure, and call the device open routine (if any). 54 */ 55 56 static int 57 copen(int startfd, char *fname, int filemode, int createmode) 58 { 59 struct pathname pn; 60 vnode_t *vp, *sdvp; 61 file_t *fp, *startfp; 62 enum vtype type; 63 int error; 64 int fd, dupfd; 65 vnode_t *startvp; 66 proc_t *p = curproc; 67 uio_seg_t seg = UIO_USERSPACE; 68 char *open_filename = fname; 69 uint32_t auditing = AU_AUDITING(); 70 char startchar; 71 72 if (filemode & (FSEARCH|FEXEC)) { 73 /* 74 * Must be one or the other and neither FREAD nor FWRITE 75 * Must not be any of FAPPEND FCREAT FTRUNC FXATTR FXATTRDIROPEN 76 * XXX: Should these just be silently ignored? 77 */ 78 if ((filemode & (FREAD|FWRITE)) || 79 (filemode & (FSEARCH|FEXEC)) == (FSEARCH|FEXEC) || 80 (filemode & (FAPPEND|FCREAT|FTRUNC|FXATTR|FXATTRDIROPEN))) 81 return (set_errno(EINVAL)); 82 } 83 84 if (startfd == AT_FDCWD) { 85 /* 86 * Regular open() 87 */ 88 startvp = NULL; 89 } else { 90 /* 91 * We're here via openat() 92 */ 93 if (copyin(fname, &startchar, sizeof (char))) 94 return (set_errno(EFAULT)); 95 96 /* 97 * if startchar is / then startfd is ignored 98 */ 99 if (startchar == '/') 100 startvp = NULL; 101 else { 102 if ((startfp = getf(startfd)) == NULL) 103 return (set_errno(EBADF)); 104 startvp = startfp->f_vnode; 105 VN_HOLD(startvp); 106 releasef(startfd); 107 } 108 } 109 110 /* 111 * Handle __openattrdirat() requests 112 */ 113 if (filemode & FXATTRDIROPEN) { 114 if (auditing && startvp != NULL) 115 audit_setfsat_path(1); 116 if (error = lookupnameat(fname, seg, FOLLOW, 117 NULLVPP, &vp, startvp)) 118 return (set_errno(error)); 119 if (startvp != NULL) 120 VN_RELE(startvp); 121 122 startvp = vp; 123 } 124 125 /* 126 * Do we need to go into extended attribute space? 127 */ 128 if (filemode & FXATTR) { 129 if (startfd == AT_FDCWD) { 130 if (copyin(fname, &startchar, sizeof (char))) 131 return (set_errno(EFAULT)); 132 133 /* 134 * If startchar == '/' then no extended attributes 135 * are looked up. 136 */ 137 if (startchar == '/') { 138 startvp = NULL; 139 } else { 140 mutex_enter(&p->p_lock); 141 startvp = PTOU(p)->u_cdir; 142 VN_HOLD(startvp); 143 mutex_exit(&p->p_lock); 144 } 145 } 146 147 /* 148 * Make sure we have a valid extended attribute request. 149 * We must either have a real fd or AT_FDCWD and a relative 150 * pathname. 151 */ 152 if (startvp == NULL) { 153 goto noxattr; 154 } 155 } 156 157 if (filemode & (FXATTR|FXATTRDIROPEN)) { 158 vattr_t vattr; 159 160 if (error = pn_get(fname, UIO_USERSPACE, &pn)) { 161 goto out; 162 } 163 164 /* 165 * In order to access hidden attribute directory the 166 * user must be able to stat() the file 167 */ 168 vattr.va_mask = AT_ALL; 169 if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) { 170 pn_free(&pn); 171 goto out; 172 } 173 174 if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 || 175 vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { 176 error = VOP_LOOKUP(startvp, "", &sdvp, &pn, 177 (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR : 178 LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(), 179 NULL, NULL, NULL); 180 } else { 181 error = EINVAL; 182 } 183 184 /* 185 * For __openattrdirat() use "." as filename to open 186 * as part of vn_openat() 187 */ 188 if (error == 0 && (filemode & FXATTRDIROPEN)) { 189 open_filename = "."; 190 seg = UIO_SYSSPACE; 191 } 192 193 pn_free(&pn); 194 if (error != 0) 195 goto out; 196 197 VN_RELE(startvp); 198 startvp = sdvp; 199 } 200 201 noxattr: 202 if ((filemode & (FREAD|FWRITE|FSEARCH|FEXEC|FXATTRDIROPEN)) != 0) { 203 if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) 204 filemode &= ~FNDELAY; 205 error = falloc((vnode_t *)NULL, filemode, &fp, &fd); 206 if (error == 0) { 207 if (auditing && startvp != NULL) 208 audit_setfsat_path(1); 209 /* 210 * Last arg is a don't-care term if 211 * !(filemode & FCREAT). 212 */ 213 error = vn_openat(open_filename, seg, filemode, 214 (int)(createmode & MODEMASK), 215 &vp, CRCREAT, PTOU(curproc)->u_cmask, 216 startvp, fd); 217 218 if (startvp != NULL) 219 VN_RELE(startvp); 220 if (error == 0) { 221 if ((vp->v_flag & VDUP) == 0) { 222 fp->f_vnode = vp; 223 mutex_exit(&fp->f_tlock); 224 /* 225 * We must now fill in the slot 226 * falloc reserved. 227 */ 228 setf(fd, fp); 229 return (fd); 230 } else { 231 /* 232 * Special handling for /dev/fd. 233 * Give up the file pointer 234 * and dup the indicated file descriptor 235 * (in v_rdev). This is ugly, but I've 236 * seen worse. 237 */ 238 unfalloc(fp); 239 dupfd = getminor(vp->v_rdev); 240 type = vp->v_type; 241 mutex_enter(&vp->v_lock); 242 vp->v_flag &= ~VDUP; 243 mutex_exit(&vp->v_lock); 244 VN_RELE(vp); 245 if (type != VCHR) 246 return (set_errno(EINVAL)); 247 if ((fp = getf(dupfd)) == NULL) { 248 setf(fd, NULL); 249 return (set_errno(EBADF)); 250 } 251 mutex_enter(&fp->f_tlock); 252 fp->f_count++; 253 mutex_exit(&fp->f_tlock); 254 setf(fd, fp); 255 releasef(dupfd); 256 } 257 return (fd); 258 } else { 259 setf(fd, NULL); 260 unfalloc(fp); 261 return (set_errno(error)); 262 } 263 } 264 } else { 265 error = EINVAL; 266 } 267 out: 268 if (startvp != NULL) 269 VN_RELE(startvp); 270 return (set_errno(error)); 271 } 272 273 #define OPENMODE32(fmode) (((fmode) & (FSEARCH | FEXEC))? \ 274 (fmode) : (fmode) - FOPEN) 275 #define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX) 276 #ifdef _LP64 277 #define OPENMODE(fmode) OPENMODE64(fmode) 278 #else 279 #define OPENMODE(fmode) OPENMODE32(fmode) 280 #endif 281 282 /* 283 * Open a file. 284 */ 285 int 286 openat(int fd, char *path, int fmode, int cmode) 287 { 288 return (copen(fd, path, OPENMODE(fmode), cmode)); 289 } 290 291 int 292 open(char *path, int fmode, int cmode) 293 { 294 return (openat(AT_FDCWD, path, fmode, cmode)); 295 } 296 297 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 298 /* 299 * Open for large files in 32-bit environment. Sets the FOFFMAX flag. 300 */ 301 int 302 openat64(int fd, char *path, int fmode, int cmode) 303 { 304 return (copen(fd, path, OPENMODE64(fmode), cmode)); 305 } 306 307 int 308 open64(char *path, int fmode, int cmode) 309 { 310 return (openat64(AT_FDCWD, path, fmode, cmode)); 311 } 312 313 #endif /* _ILP32 || _SYSCALL32_IMPL */ 314 315 #ifdef _SYSCALL32_IMPL 316 /* 317 * Open for 32-bit compatibility on 64-bit kernel 318 */ 319 int 320 openat32(int fd, char *path, int fmode, int cmode) 321 { 322 return (copen(fd, path, OPENMODE32(fmode), cmode)); 323 } 324 325 int 326 open32(char *path, int fmode, int cmode) 327 { 328 return (openat32(AT_FDCWD, path, fmode, cmode)); 329 } 330 331 #endif /* _SYSCALL32_IMPL */