kernel_proxy.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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 "nacl_io/typed_mount_factory.h" 29#include "sdk_util/auto_lock.h" 30#include "sdk_util/ref_object.h" 31 32#ifndef MAXPATHLEN 33#define MAXPATHLEN 256 34#endif 35 36namespace nacl_io { 37 38KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) { 39} 40 41KernelProxy::~KernelProxy() { 42 // Clean up the MountFactories. 43 for (MountFactoryMap_t::iterator i = factories_.begin(); 44 i != factories_.end(); 45 ++i) { 46 delete i->second; 47 } 48 49 delete ppapi_; 50} 51 52void KernelProxy::Init(PepperInterface* ppapi) { 53 ppapi_ = ppapi; 54 dev_ = 1; 55 56 factories_["memfs"] = new TypedMountFactory<MountMem>; 57 factories_["dev"] = new TypedMountFactory<MountDev>; 58 factories_["html5fs"] = new TypedMountFactory<MountHtml5Fs>; 59 factories_["httpfs"] = new TypedMountFactory<MountHttp>; 60 factories_["passthroughfs"] = new TypedMountFactory<MountPassthrough>; 61 62 int result; 63 result = mount("", "/", "passthroughfs", 0, NULL); 64 assert(result == 0); 65 66 result = mount("", "/dev", "dev", 0, NULL); 67 assert(result == 0); 68 69 // Open the first three in order to get STDIN, STDOUT, STDERR 70 open("/dev/stdin", O_RDONLY); 71 open("/dev/stdout", O_WRONLY); 72 open("/dev/stderr", O_WRONLY); 73} 74 75int KernelProxy::open_resource(const char* path) { 76 ScopedMount mnt; 77 Path rel; 78 79 Error error = AcquireMountAndRelPath(path, &mnt, &rel); 80 if (error) { 81 errno = error; 82 return -1; 83 } 84 85 ScopedMountNode node; 86 error = mnt->OpenResource(rel, &node); 87 if (error) { 88 // OpenResource failed, try Open(). 89 error = mnt->Open(rel, O_RDONLY, &node); 90 if (error) { 91 errno = error; 92 return -1; 93 } 94 } 95 96 ScopedKernelHandle handle(new KernelHandle(mnt, node)); 97 error = handle->Init(O_RDONLY); 98 if (error) { 99 errno = error; 100 return -1; 101 } 102 103 return AllocateFD(handle); 104} 105 106int KernelProxy::open(const char* path, int oflags) { 107 ScopedMount mnt; 108 ScopedMountNode node; 109 110 Error error = AcquireMountAndNode(path, oflags, &mnt, &node); 111 if (error) { 112 errno = error; 113 return -1; 114 } 115 116 ScopedKernelHandle handle(new KernelHandle(mnt, node)); 117 error = handle->Init(oflags); 118 if (error) { 119 errno = error; 120 return -1; 121 } 122 123 return AllocateFD(handle); 124} 125 126int KernelProxy::close(int fd) { 127 ScopedKernelHandle handle; 128 Error error = AcquireHandle(fd, &handle); 129 if (error) { 130 errno = error; 131 return -1; 132 } 133 134 // Remove the FD from the process open file descriptor map 135 FreeFD(fd); 136 return 0; 137} 138 139int KernelProxy::dup(int oldfd) { 140 ScopedKernelHandle handle; 141 Error error = AcquireHandle(oldfd, &handle); 142 if (error) { 143 errno = error; 144 return -1; 145 } 146 147 return AllocateFD(handle); 148} 149 150int KernelProxy::dup2(int oldfd, int newfd) { 151 // If it's the same file handle, just return 152 if (oldfd == newfd) 153 return newfd; 154 155 ScopedKernelHandle old_handle; 156 Error error = AcquireHandle(oldfd, &old_handle); 157 if (error) { 158 errno = error; 159 return -1; 160 } 161 162 FreeAndReassignFD(newfd, old_handle); 163 return newfd; 164} 165 166int KernelProxy::chdir(const char* path) { 167 Error error = SetCWD(path); 168 if (error) { 169 errno = error; 170 return -1; 171 } 172 return 0; 173} 174 175char* KernelProxy::getcwd(char* buf, size_t size) { 176 std::string cwd = GetCWD(); 177 178 if (size <= 0) { 179 errno = EINVAL; 180 return NULL; 181 } 182 183 // If size is 0, allocate as much as we need. 184 if (size == 0) { 185 size = cwd.size() + 1; 186 } 187 188 // Verify the buffer is large enough 189 if (size <= cwd.size()) { 190 errno = ERANGE; 191 return NULL; 192 } 193 194 // Allocate the buffer if needed 195 if (buf == NULL) { 196 buf = static_cast<char*>(malloc(size)); 197 } 198 199 strcpy(buf, cwd.c_str()); 200 return buf; 201} 202 203char* KernelProxy::getwd(char* buf) { 204 if (NULL == buf) { 205 errno = EFAULT; 206 return NULL; 207 } 208 return getcwd(buf, MAXPATHLEN); 209} 210 211int KernelProxy::chmod(const char* path, mode_t mode) { 212 int fd = KernelProxy::open(path, O_RDONLY); 213 if (-1 == fd) 214 return -1; 215 216 int result = fchmod(fd, mode); 217 close(fd); 218 return result; 219} 220 221int KernelProxy::chown(const char* path, uid_t owner, gid_t group) { 222 return 0; 223} 224 225int KernelProxy::fchown(int fd, uid_t owner, gid_t group) { 226 return 0; 227} 228 229int KernelProxy::lchown(const char* path, uid_t owner, gid_t group) { 230 return 0; 231} 232 233int KernelProxy::utime(const char* filename, const struct utimbuf* times) { 234 return 0; 235} 236 237int KernelProxy::mkdir(const char* path, mode_t mode) { 238 ScopedMount mnt; 239 Path rel; 240 241 Error error = AcquireMountAndRelPath(path, &mnt, &rel); 242 if (error) { 243 errno = error; 244 return -1; 245 } 246 247 error = mnt->Mkdir(rel, mode); 248 if (error) { 249 errno = error; 250 return -1; 251 } 252 253 return 0; 254} 255 256int KernelProxy::rmdir(const char* path) { 257 ScopedMount mnt; 258 Path rel; 259 260 Error error = AcquireMountAndRelPath(path, &mnt, &rel); 261 if (error) { 262 errno = error; 263 return -1; 264 } 265 266 error = mnt->Rmdir(rel); 267 if (error) { 268 errno = error; 269 return -1; 270 } 271 272 return 0; 273} 274 275int KernelProxy::stat(const char* path, struct stat* buf) { 276 int fd = open(path, O_RDONLY); 277 if (-1 == fd) 278 return -1; 279 280 int result = fstat(fd, buf); 281 close(fd); 282 return result; 283} 284 285 286int KernelProxy::mount(const char* source, 287 const char* target, 288 const char* filesystemtype, 289 unsigned long mountflags, 290 const void* data) { 291 std::string abs_path = GetAbsParts(target).Join(); 292 293 // Find a factory of that type 294 MountFactoryMap_t::iterator factory = factories_.find(filesystemtype); 295 if (factory == factories_.end()) { 296 errno = ENODEV; 297 return -1; 298 } 299 300 // Create a map of settings 301 StringMap_t smap; 302 smap["SOURCE"] = source; 303 smap["TARGET"] = abs_path; 304 305 if (data) { 306 char* str = strdup(static_cast<const char*>(data)); 307 char* ptr = strtok(str, ","); 308 char* val; 309 while (ptr != NULL) { 310 val = strchr(ptr, '='); 311 if (val) { 312 *val = 0; 313 smap[ptr] = val + 1; 314 } else { 315 smap[ptr] = "TRUE"; 316 } 317 ptr = strtok(NULL, ","); 318 } 319 free(str); 320 } 321 322 ScopedMount mnt; 323 Error error = factory->second->CreateMount(dev_++, smap, ppapi_, &mnt); 324 if (error) { 325 errno = error; 326 return -1; 327 } 328 329 error = AttachMountAtPath(mnt, abs_path); 330 if (error) { 331 errno = error; 332 return -1; 333 } 334 335 return 0; 336} 337 338int KernelProxy::umount(const char* path) { 339 Error error = DetachMountAtPath(path); 340 if (error) { 341 errno = error; 342 return -1; 343 } 344 return 0; 345} 346 347ssize_t KernelProxy::read(int fd, void* buf, size_t nbytes) { 348 ScopedKernelHandle handle; 349 Error error = AcquireHandle(fd, &handle); 350 if (error) { 351 errno = error; 352 return -1; 353 } 354 355 int cnt = 0; 356 error = handle->Read(buf, nbytes, &cnt); 357 if (error) { 358 errno = error; 359 return -1; 360 } 361 362 return cnt; 363} 364 365ssize_t KernelProxy::write(int fd, const void* buf, size_t nbytes) { 366 ScopedKernelHandle handle; 367 Error error = AcquireHandle(fd, &handle); 368 if (error) { 369 errno = error; 370 return -1; 371 } 372 373 int cnt = 0; 374 error = handle->Write(buf, nbytes, &cnt); 375 if (error) { 376 errno = error; 377 return -1; 378 } 379 380 return cnt; 381} 382 383int KernelProxy::fstat(int fd, struct stat* buf) { 384 ScopedKernelHandle handle; 385 Error error = AcquireHandle(fd, &handle); 386 if (error) { 387 errno = error; 388 return -1; 389 } 390 391 error = handle->node()->GetStat(buf); 392 if (error) { 393 errno = error; 394 return -1; 395 } 396 397 return 0; 398} 399 400int KernelProxy::getdents(int fd, void* buf, unsigned int count) { 401 ScopedKernelHandle handle; 402 Error error = AcquireHandle(fd, &handle); 403 if (error) { 404 errno = error; 405 return -1; 406 } 407 408 int cnt = 0; 409 error = handle->GetDents(static_cast<dirent*>(buf), count, &cnt); 410 if (error) 411 errno = error; 412 413 return cnt; 414} 415 416int KernelProxy::ftruncate(int fd, off_t length) { 417 ScopedKernelHandle handle; 418 Error error = AcquireHandle(fd, &handle); 419 if (error) { 420 errno = error; 421 return -1; 422 } 423 424 error = handle->node()->FTruncate(length); 425 if (error) { 426 errno = error; 427 return -1; 428 } 429 430 return 0; 431} 432 433int KernelProxy::fsync(int fd) { 434 ScopedKernelHandle handle; 435 Error error = AcquireHandle(fd, &handle); 436 if (error) { 437 errno = error; 438 return -1; 439 } 440 441 error = handle->node()->FSync(); 442 if (error) { 443 errno = error; 444 return -1; 445 } 446 447 return 0; 448} 449 450int KernelProxy::isatty(int fd) { 451 ScopedKernelHandle handle; 452 Error error = AcquireHandle(fd, &handle); 453 if (error) { 454 errno = error; 455 return -1; 456 } 457 458 error = handle->node()->IsaTTY(); 459 if (error) { 460 errno = error; 461 return -1; 462 } 463 464 return 0; 465} 466 467int KernelProxy::ioctl(int d, int request, char* argp) { 468 ScopedKernelHandle handle; 469 Error error = AcquireHandle(d, &handle); 470 if (error) { 471 errno = error; 472 return -1; 473 } 474 475 error = handle->node()->Ioctl(request, argp); 476 if (error) { 477 errno = error; 478 return -1; 479 } 480 481 return 0; 482} 483 484off_t KernelProxy::lseek(int fd, off_t offset, int whence) { 485 ScopedKernelHandle handle; 486 Error error = AcquireHandle(fd, &handle); 487 if (error) { 488 errno = error; 489 return -1; 490 } 491 492 off_t new_offset; 493 error = handle->Seek(offset, whence, &new_offset); 494 if (error) { 495 errno = error; 496 return -1; 497 } 498 499 return new_offset; 500} 501 502int KernelProxy::unlink(const char* path) { 503 ScopedMount mnt; 504 Path rel; 505 506 Error error = AcquireMountAndRelPath(path, &mnt, &rel); 507 if (error) { 508 errno = error; 509 return -1; 510 } 511 512 error = mnt->Unlink(rel); 513 if (error) { 514 errno = error; 515 return -1; 516 } 517 518 return 0; 519} 520 521int KernelProxy::remove(const char* path) { 522 ScopedMount mnt; 523 Path rel; 524 525 Error error = AcquireMountAndRelPath(path, &mnt, &rel); 526 if (error) { 527 errno = error; 528 return -1; 529 } 530 531 error = mnt->Remove(rel); 532 if (error) { 533 errno = error; 534 return -1; 535 } 536 537 return 0; 538} 539 540// TODO(noelallen): Needs implementation. 541int KernelProxy::fchmod(int fd, int mode) { 542 ScopedKernelHandle handle; 543 Error error = AcquireHandle(fd, &handle); 544 if (error) { 545 errno = error; 546 return -1; 547 } 548 549 return 0; 550} 551 552int KernelProxy::access(const char* path, int amode) { 553 ScopedMount mnt; 554 Path rel; 555 556 Error error = AcquireMountAndRelPath(path, &mnt, &rel); 557 if (error) { 558 errno = error; 559 return -1; 560 } 561 562 error = mnt->Access(rel, amode); 563 if (error) { 564 errno = error; 565 return -1; 566 } 567 return 0; 568} 569 570// TODO(noelallen): Needs implementation. 571int KernelProxy::link(const char* oldpath, const char* newpath) { 572 errno = EINVAL; 573 return -1; 574} 575 576int KernelProxy::symlink(const char* oldpath, const char* newpath) { 577 errno = EINVAL; 578 return -1; 579} 580 581void* KernelProxy::mmap(void* addr, 582 size_t length, 583 int prot, 584 int flags, 585 int fd, 586 size_t offset) { 587 // We shouldn't be getting anonymous mmaps here. 588 assert((flags & MAP_ANONYMOUS) == 0); 589 assert(fd != -1); 590 591 ScopedKernelHandle handle; 592 Error error = AcquireHandle(fd, &handle); 593 if (error) { 594 errno = error; 595 return MAP_FAILED; 596 } 597 598 void* new_addr; 599 error = handle->node()->MMap(addr, length, prot, flags, offset, &new_addr); 600 if (error) { 601 errno = error; 602 return MAP_FAILED; 603 } 604 605 return new_addr; 606} 607 608int KernelProxy::munmap(void* addr, size_t length) { 609 // NOTE: The comment below is from a previous discarded implementation that 610 // tracks mmap'd regions. For simplicity, we no longer do this; because we 611 // "snapshot" the contents of the file in mmap(), and don't support 612 // write-back or updating the mapped region when the file is written, holding 613 // on to the KernelHandle is pointless. 614 // 615 // If we ever do, these threading issues should be considered. 616 617 // 618 // WARNING: this function may be called by free(). 619 // 620 // There is a potential deadlock scenario: 621 // Thread 1: open() -> takes lock1 -> free() -> takes lock2 622 // Thread 2: free() -> takes lock2 -> munmap() -> takes lock1 623 // 624 // Note that open() above could be any function that takes a lock that is 625 // shared with munmap (this includes munmap!) 626 // 627 // To prevent this, we avoid taking locks in munmap() that are used by other 628 // nacl_io functions that may call free. Specifically, we only take the 629 // mmap_lock, which is only shared with mmap() above. There is still a 630 // possibility of deadlock if mmap() or munmap() calls free(), so this is not 631 // allowed. 632 // 633 // Unfortunately, munmap still needs to acquire other locks; see the call to 634 // ReleaseHandle below which takes the process lock. This is safe as long as 635 // this is never executed from free() -- we can be reasonably sure this is 636 // true, because malloc only makes anonymous mmap() requests, and should only 637 // be munmapping those allocations. We never add to mmap_info_list_ for 638 // anonymous maps, so the unmap_list should always be empty when called from 639 // free(). 640 return 0; 641} 642 643} // namespace nacl_io 644 645