kernel_proxy.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1/* Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5#include "nacl_io/kernel_proxy.h" 6 7#include <assert.h> 8#include <errno.h> 9#include <fcntl.h> 10#include <pthread.h> 11#include <string.h> 12#include <iterator> 13#include <string> 14 15#include "nacl_io/kernel_handle.h" 16#include "nacl_io/kernel_wrap_real.h" 17#include "nacl_io/mount.h" 18#include "nacl_io/mount_dev.h" 19#include "nacl_io/mount_html5fs.h" 20#include "nacl_io/mount_http.h" 21#include "nacl_io/mount_mem.h" 22#include "nacl_io/mount_node.h" 23#include "nacl_io/mount_passthrough.h" 24#include "nacl_io/osmman.h" 25#include "nacl_io/osstat.h" 26#include "nacl_io/path.h" 27#include "nacl_io/pepper_interface.h" 28#include "utils/auto_lock.h" 29#include "utils/ref_object.h" 30 31#ifndef MAXPATHLEN 32#define MAXPATHLEN 256 33#endif 34 35// TODO(noelallen) : Grab/Redefine these in the kernel object once available. 36#define USR_ID 1002 37#define GRP_ID 1003 38 39 40 41KernelProxy::KernelProxy() 42 : dev_(0), 43 ppapi_(NULL) { 44} 45 46KernelProxy::~KernelProxy() { 47 delete ppapi_; 48} 49 50void KernelProxy::Init(PepperInterface* ppapi) { 51 ppapi_ = ppapi; 52 cwd_ = "/"; 53 dev_ = 1; 54 55 factories_["memfs"] = MountMem::Create<MountMem>; 56 factories_["dev"] = MountDev::Create<MountDev>; 57 factories_["html5fs"] = MountHtml5Fs::Create<MountHtml5Fs>; 58 factories_["httpfs"] = MountHttp::Create<MountHttp>; 59 factories_["passthroughfs"] = MountPassthrough::Create<MountPassthrough>; 60 61 // Create passthrough mount at root 62 StringMap_t smap; 63 mounts_["/"] = MountPassthrough::Create<MountPassthrough>( 64 dev_++, smap, ppapi_); 65 mounts_["/dev"] = MountDev::Create<MountDev>(dev_++, smap, ppapi_); 66 67 // Open the first three in order to get STDIN, STDOUT, STDERR 68 open("/dev/stdin", O_RDONLY); 69 open("/dev/stdout", O_WRONLY); 70 open("/dev/stderr", O_WRONLY); 71} 72 73int KernelProxy::open(const char *path, int oflags) { 74 Path rel; 75 76 Mount* mnt = AcquireMountAndPath(path, &rel); 77 if (mnt == NULL) return -1; 78 79 MountNode* node = mnt->Open(rel, oflags); 80 if (node == NULL) { 81 ReleaseMount(mnt); 82 return -1; 83 } 84 85 KernelHandle* handle = new KernelHandle(mnt, node, oflags); 86 int fd = AllocateFD(handle); 87 mnt->AcquireNode(node); 88 89 ReleaseHandle(handle); 90 ReleaseMount(mnt); 91 92 return fd; 93} 94 95int KernelProxy::close(int fd) { 96 KernelHandle* handle = AcquireHandle(fd); 97 98 if (NULL == handle) return -1; 99 100 Mount* mount = handle->mount_; 101 // Acquire the mount to ensure FreeFD doesn't prematurely destroy it. 102 mount->Acquire(); 103 104 // FreeFD will release the handle/mount held by this fd. 105 FreeFD(fd); 106 107 // If this handle is the last reference to its node, releasing it will close 108 // the node. 109 ReleaseHandle(handle); 110 111 // Finally, release the mount. 112 mount->Release(); 113 114 return 0; 115} 116 117int KernelProxy::dup(int oldfd) { 118 KernelHandle* handle = AcquireHandle(oldfd); 119 if (NULL == handle) return -1; 120 121 int newfd = AllocateFD(handle); 122 ReleaseHandle(handle); 123 124 return newfd; 125} 126 127int KernelProxy::dup2(int oldfd, int newfd) { 128 // If it's the same file handle, just return 129 if (oldfd == newfd) return newfd; 130 131 KernelHandle* old_handle = AcquireHandle(oldfd); 132 if (NULL == old_handle) return -1; 133 134 FreeAndReassignFD(newfd, old_handle); 135 ReleaseHandle(old_handle); 136 return newfd; 137} 138 139 140char* KernelProxy::getcwd(char* buf, size_t size) { 141 AutoLock lock(&process_lock_); 142 if (size <= 0) { 143 errno = EINVAL; 144 return NULL; 145 } 146 // If size is 0, allocate as much as we need. 147 if (size == 0) { 148 size = cwd_.size() + 1; 149 } 150 151 // Verify the buffer is large enough 152 if (size <= cwd_.size()) { 153 errno = ERANGE; 154 return NULL; 155 } 156 157 // Allocate the buffer if needed 158 if (buf == NULL) { 159 buf = static_cast<char*>(malloc(size)); 160 } 161 162 strcpy(buf, cwd_.c_str()); 163 return buf; 164} 165 166char* KernelProxy::getwd(char* buf) { 167 if (NULL == buf) { 168 errno = EFAULT; 169 return NULL; 170 } 171 return getcwd(buf, MAXPATHLEN); 172} 173 174int KernelProxy::chmod(const char *path, mode_t mode) { 175 int fd = KernelProxy::open(path, O_RDWR); 176 if (-1 == fd) return -1; 177 178 int ret = fchmod(fd, mode); 179 close(fd); 180 return ret; 181} 182 183int KernelProxy::mkdir(const char *path, mode_t mode) { 184 Path rel; 185 Mount* mnt = AcquireMountAndPath(path, &rel); 186 if (mnt == NULL) return -1; 187 188 int val = mnt->Mkdir(rel, mode); 189 ReleaseMount(mnt); 190 return val; 191} 192 193int KernelProxy::rmdir(const char *path) { 194 Path rel; 195 Mount* mnt = AcquireMountAndPath(path, &rel); 196 if (mnt == NULL) return -1; 197 198 int val = mnt->Rmdir(rel); 199 ReleaseMount(mnt); 200 return val; 201} 202 203int KernelProxy::stat(const char *path, struct stat *buf) { 204 int fd = open(path, O_RDONLY); 205 if (-1 == fd) return -1; 206 207 int ret = fstat(fd, buf); 208 close(fd); 209 return ret; 210} 211 212int KernelProxy::chdir(const char* path) { 213 struct stat statbuf; 214 if (stat(path, &statbuf) == -1) 215 return -1; 216 217 bool is_dir = (statbuf.st_mode & S_IFDIR) != 0; 218 if (is_dir) { 219 AutoLock lock(&process_lock_); 220 cwd_ = GetAbsPathLocked(path).Join(); 221 return 0; 222 } 223 224 errno = ENOTDIR; 225 return -1; 226} 227 228int KernelProxy::mount(const char *source, const char *target, 229 const char *filesystemtype, unsigned long mountflags, 230 const void *data) { 231 // See if it's already mounted 232 std::string abs_targ; 233 234 // Scope this lock to prevent holding both process and kernel locks 235 { 236 AutoLock lock(&process_lock_); 237 abs_targ = GetAbsPathLocked(target).Join(); 238 } 239 240 AutoLock lock(&kernel_lock_); 241 if (mounts_.find(abs_targ) != mounts_.end()) { 242 errno = EBUSY; 243 return -1; 244 } 245 246 // Find a factory of that type 247 MountFactoryMap_t::iterator factory = factories_.find(filesystemtype); 248 if (factory == factories_.end()) { 249 errno = ENODEV; 250 return -1; 251 } 252 253 StringMap_t smap; 254 smap["SOURCE"] = source; 255 smap["TARGET"] = abs_targ; 256 257 if (data) { 258 char* str = strdup(static_cast<const char *>(data)); 259 char* ptr = strtok(str,","); 260 char* val; 261 while (ptr != NULL) { 262 val = strchr(ptr, '='); 263 if (val) { 264 *val = 0; 265 smap[ptr] = val + 1; 266 } else { 267 smap[ptr] = "TRUE"; 268 } 269 ptr = strtok(NULL, ","); 270 } 271 free(str); 272 } 273 274 Mount* mnt = factory->second(dev_++, smap, ppapi_); 275 if (mnt) { 276 mounts_[abs_targ] = mnt; 277 return 0; 278 } 279 errno = EINVAL; 280 return -1; 281} 282 283int KernelProxy::umount(const char *path) { 284 Path abs_path; 285 286 // Scope this lock to prevent holding both process and kernel locks 287 { 288 AutoLock lock(&process_lock_); 289 abs_path = GetAbsPathLocked(path); 290 } 291 292 AutoLock lock(&kernel_lock_); 293 MountMap_t::iterator it = mounts_.find(abs_path.Join()); 294 295 if (mounts_.end() == it) { 296 errno = EINVAL; 297 return -1; 298 } 299 300 if (it->second->RefCount() != 1) { 301 errno = EBUSY; 302 return -1; 303 } 304 305 it->second->Release(); 306 mounts_.erase(it); 307 return 0; 308} 309 310ssize_t KernelProxy::read(int fd, void *buf, size_t nbytes) { 311 KernelHandle* handle = AcquireHandle(fd); 312 313 // check if fd is valid and handle exists 314 if (NULL == handle) return -1; 315 316 AutoLock lock(&handle->lock_); 317 ssize_t cnt = handle->node_->Read(handle->offs_, buf, nbytes); 318 if (cnt > 0) handle->offs_ += cnt; 319 320 ReleaseHandle(handle); 321 return cnt; 322} 323 324ssize_t KernelProxy::write(int fd, const void *buf, size_t nbytes) { 325 KernelHandle* handle = AcquireHandle(fd); 326 327 // check if fd is valid and handle exists 328 if (NULL == handle) return -1; 329 330 AutoLock lock(&handle->lock_); 331 ssize_t cnt = handle->node_->Write(handle->offs_, buf, nbytes); 332 if (cnt > 0) handle->offs_ += cnt; 333 334 ReleaseHandle(handle); 335 return cnt; 336} 337 338int KernelProxy::fstat(int fd, struct stat* buf) { 339 KernelHandle* handle = AcquireHandle(fd); 340 341 // check if fd is valid and handle exists 342 if (NULL == handle) return -1; 343 344 int ret = handle->node_->GetStat(buf); 345 ReleaseHandle(handle); 346 return ret; 347} 348 349int KernelProxy::getdents(int fd, void* buf, unsigned int count) { 350 KernelHandle* handle = AcquireHandle(fd); 351 352 // check if fd is valid and handle exists 353 if (NULL == handle) return -1; 354 355 AutoLock lock(&handle->lock_); 356 int cnt = handle->node_->GetDents(handle->offs_, 357 static_cast<dirent *>(buf), count); 358 359 if (cnt > 0) handle->offs_ += cnt; 360 361 ReleaseHandle(handle); 362 return cnt; 363} 364 365int KernelProxy::ftruncate(int fd, off_t length) { 366 KernelHandle* handle = AcquireHandle(fd); 367 368 // check if fd is valid and handle exists 369 if (NULL == handle) return -1; 370 int ret = handle->node_->FTruncate(length); 371 372 ReleaseHandle(handle); 373 return ret; 374} 375 376int KernelProxy::fsync(int fd) { 377 KernelHandle* handle = AcquireHandle(fd); 378 379 // check if fd is valid and handle exists 380 if (NULL == handle) return -1; 381 int ret = handle->node_->FSync(); 382 383 ReleaseHandle(handle); 384 return ret; 385} 386 387int KernelProxy::isatty(int fd) { 388 KernelHandle* handle = AcquireHandle(fd); 389 390 // check if fd is valid and handle exists 391 if (NULL == handle) return -1; 392 int ret = handle->node_->IsaTTY(); 393 394 ReleaseHandle(handle); 395 return ret; 396} 397 398off_t KernelProxy::lseek(int fd, off_t offset, int whence) { 399 KernelHandle* handle = AcquireHandle(fd); 400 401 // check if fd is valid and handle exists 402 if (NULL == handle) return -1; 403 404 AutoLock lock(&handle->lock_); 405 int ret = handle->Seek(offset, whence); 406 407 ReleaseHandle(handle); 408 return ret; 409} 410 411int KernelProxy::unlink(const char* path) { 412 Path rel; 413 Mount* mnt = AcquireMountAndPath(path, &rel); 414 if (mnt == NULL) return -1; 415 416 int val = mnt->Unlink(rel); 417 ReleaseMount(mnt); 418 return val; 419} 420 421int KernelProxy::remove(const char* path) { 422 Path rel; 423 Mount* mnt = AcquireMountAndPath(path, &rel); 424 if (mnt == NULL) return -1; 425 426 int val = mnt->Remove(rel); 427 ReleaseMount(mnt); 428 return val; 429} 430 431// TODO(noelallen): Needs implementation. 432int KernelProxy::fchmod(int fd, int mode) { 433 errno = EINVAL; 434 return -1; 435} 436 437int KernelProxy::access(const char* path, int amode) { 438 errno = EINVAL; 439 return -1; 440} 441 442int KernelProxy::link(const char* oldpath, const char* newpath) { 443 errno = EINVAL; 444 return -1; 445} 446 447int KernelProxy::symlink(const char* oldpath, const char* newpath) { 448 errno = EINVAL; 449 return -1; 450} 451 452void* KernelProxy::mmap(void* addr, size_t length, int prot, int flags, int fd, 453 size_t offset) { 454 // We shouldn't be getting anonymous mmaps here. 455 assert((flags & MAP_ANONYMOUS) == 0); 456 assert(fd != -1); 457 458 KernelHandle* handle = AcquireHandle(fd); 459 460 if (NULL == handle) 461 return MAP_FAILED; 462 463 void* new_addr; 464 { 465 AutoLock lock(&handle->lock_); 466 new_addr = handle->node_->MMap(addr, length, prot, flags, offset); 467 if (new_addr == MAP_FAILED) { 468 ReleaseHandle(handle); 469 return MAP_FAILED; 470 } 471 } 472 473 ReleaseHandle(handle); 474 return new_addr; 475} 476 477int KernelProxy::munmap(void* addr, size_t length) { 478 // NOTE: The comment below is from a previous discarded implementation that 479 // tracks mmap'd regions. For simplicity, we no longer do this; because we 480 // "snapshot" the contents of the file in mmap(), and don't support 481 // write-back or updating the mapped region when the file is written, holding 482 // on to the KernelHandle is pointless. 483 // 484 // If we ever do, these threading issues should be considered. 485 486 // 487 // WARNING: this function may be called by free(). 488 // 489 // There is a potential deadlock scenario: 490 // Thread 1: open() -> takes lock1 -> free() -> takes lock2 491 // Thread 2: free() -> takes lock2 -> munmap() -> takes lock1 492 // 493 // Note that open() above could be any function that takes a lock that is 494 // shared with munmap (this includes munmap!) 495 // 496 // To prevent this, we avoid taking locks in munmap() that are used by other 497 // nacl_io functions that may call free. Specifically, we only take the 498 // mmap_lock, which is only shared with mmap() above. There is still a 499 // possibility of deadlock if mmap() or munmap() calls free(), so this is not 500 // allowed. 501 // 502 // Unfortunately, munmap still needs to acquire other locks; see the call to 503 // ReleaseHandle below which takes the process lock. This is safe as long as 504 // this is never executed from free() -- we can be reasonably sure this is 505 // true, because malloc only makes anonymous mmap() requests, and should only 506 // be munmapping those allocations. We never add to mmap_info_list_ for 507 // anonymous maps, so the unmap_list should always be empty when called from 508 // free(). 509 return 0; 510} 511 512int KernelProxy::open_resource(const char* path) { 513 Path rel; 514 515 Mount* mnt = AcquireMountAndPath(path, &rel); 516 if (mnt == NULL) return -1; 517 518 MountNode* node = mnt->OpenResource(rel); 519 if (node == NULL) { 520 node = mnt->Open(rel, O_RDONLY); 521 if (node == NULL) { 522 ReleaseMount(mnt); 523 return -1; 524 } 525 } 526 527 // OpenResource failed, try Open(). 528 529 KernelHandle* handle = new KernelHandle(mnt, node, O_RDONLY); 530 int fd = AllocateFD(handle); 531 mnt->AcquireNode(node); 532 533 ReleaseHandle(handle); 534 ReleaseMount(mnt); 535 536 return fd; 537} 538