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