VirtualFileSystem.cpp 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/LexicalPath.h>
  27. #include <AK/Singleton.h>
  28. #include <AK/StringBuilder.h>
  29. #include <Kernel/Debug.h>
  30. #include <Kernel/Devices/BlockDevice.h>
  31. #include <Kernel/FileSystem/Custody.h>
  32. #include <Kernel/FileSystem/FileBackedFileSystem.h>
  33. #include <Kernel/FileSystem/FileDescription.h>
  34. #include <Kernel/FileSystem/FileSystem.h>
  35. #include <Kernel/FileSystem/VirtualFileSystem.h>
  36. #include <Kernel/KSyms.h>
  37. #include <Kernel/Process.h>
  38. #include <LibC/errno_numbers.h>
  39. namespace Kernel {
  40. static AK::Singleton<VFS> s_the;
  41. static constexpr int symlink_recursion_limit { 5 }; // FIXME: increase?
  42. static constexpr int root_mount_flags = MS_NODEV | MS_NOSUID | MS_RDONLY;
  43. UNMAP_AFTER_INIT void VFS::initialize()
  44. {
  45. s_the.ensure_instance();
  46. }
  47. VFS& VFS::the()
  48. {
  49. return *s_the;
  50. }
  51. UNMAP_AFTER_INIT VFS::VFS()
  52. {
  53. }
  54. UNMAP_AFTER_INIT VFS::~VFS()
  55. {
  56. }
  57. InodeIdentifier VFS::root_inode_id() const
  58. {
  59. VERIFY(m_root_inode);
  60. return m_root_inode->identifier();
  61. }
  62. KResult VFS::mount(FS& file_system, Custody& mount_point, int flags)
  63. {
  64. LOCKER(m_lock);
  65. auto& inode = mount_point.inode();
  66. dbgln("VFS: Mounting {} at {} (inode: {}) with flags {}",
  67. file_system.class_name(),
  68. mount_point.absolute_path(),
  69. inode.identifier(),
  70. flags);
  71. // FIXME: check that this is not already a mount point
  72. Mount mount { file_system, &mount_point, flags };
  73. m_mounts.append(move(mount));
  74. return KSuccess;
  75. }
  76. KResult VFS::bind_mount(Custody& source, Custody& mount_point, int flags)
  77. {
  78. LOCKER(m_lock);
  79. dbgln("VFS: Bind-mounting {} at {}", source.absolute_path(), mount_point.absolute_path());
  80. // FIXME: check that this is not already a mount point
  81. Mount mount { source.inode(), mount_point, flags };
  82. m_mounts.append(move(mount));
  83. return KSuccess;
  84. }
  85. KResult VFS::remount(Custody& mount_point, int new_flags)
  86. {
  87. LOCKER(m_lock);
  88. dbgln("VFS: Remounting {}", mount_point.absolute_path());
  89. Mount* mount = find_mount_for_guest(mount_point.inode());
  90. if (!mount)
  91. return ENODEV;
  92. mount->set_flags(new_flags);
  93. return KSuccess;
  94. }
  95. KResult VFS::unmount(Inode& guest_inode)
  96. {
  97. LOCKER(m_lock);
  98. dbgln("VFS: unmount called with inode {}", guest_inode.identifier());
  99. for (size_t i = 0; i < m_mounts.size(); ++i) {
  100. auto& mount = m_mounts.at(i);
  101. if (&mount.guest() == &guest_inode) {
  102. auto result = mount.guest_fs().prepare_to_unmount();
  103. if (result.is_error()) {
  104. dbgln("VFS: Failed to unmount!");
  105. return result;
  106. }
  107. dbgln("VFS: found fs {} at mount index {}! Unmounting...", mount.guest_fs().fsid(), i);
  108. m_mounts.unstable_take(i);
  109. return KSuccess;
  110. }
  111. }
  112. dbgln("VFS: Nothing mounted on inode {}", guest_inode.identifier());
  113. return ENODEV;
  114. }
  115. bool VFS::mount_root(FS& file_system)
  116. {
  117. if (m_root_inode) {
  118. dmesgln("VFS: mount_root can't mount another root");
  119. return false;
  120. }
  121. Mount mount { file_system, nullptr, root_mount_flags };
  122. auto root_inode = file_system.root_inode();
  123. if (!root_inode->is_directory()) {
  124. dmesgln("VFS: root inode ({}) for / is not a directory :(", root_inode->identifier());
  125. return false;
  126. }
  127. m_root_inode = move(root_inode);
  128. dmesgln("VFS: mounted root from {} ({})", file_system.class_name(), static_cast<FileBackedFS&>(file_system).file_description().absolute_path());
  129. m_mounts.append(move(mount));
  130. return true;
  131. }
  132. auto VFS::find_mount_for_host(Inode& inode) -> Mount*
  133. {
  134. for (auto& mount : m_mounts) {
  135. if (mount.host() == &inode)
  136. return &mount;
  137. }
  138. return nullptr;
  139. }
  140. auto VFS::find_mount_for_host(InodeIdentifier id) -> Mount*
  141. {
  142. for (auto& mount : m_mounts) {
  143. if (mount.host() && mount.host()->identifier() == id)
  144. return &mount;
  145. }
  146. return nullptr;
  147. }
  148. auto VFS::find_mount_for_guest(Inode& inode) -> Mount*
  149. {
  150. for (auto& mount : m_mounts) {
  151. if (&mount.guest() == &inode)
  152. return &mount;
  153. }
  154. return nullptr;
  155. }
  156. auto VFS::find_mount_for_guest(InodeIdentifier id) -> Mount*
  157. {
  158. for (auto& mount : m_mounts) {
  159. if (mount.guest().identifier() == id)
  160. return &mount;
  161. }
  162. return nullptr;
  163. }
  164. bool VFS::is_vfs_root(InodeIdentifier inode) const
  165. {
  166. return inode == root_inode_id();
  167. }
  168. KResult VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::DirectoryEntryView&)> callback)
  169. {
  170. return dir_inode.traverse_as_directory([&](auto& entry) {
  171. InodeIdentifier resolved_inode;
  172. if (auto mount = find_mount_for_host(entry.inode))
  173. resolved_inode = mount->guest().identifier();
  174. else
  175. resolved_inode = entry.inode;
  176. // FIXME: This is now broken considering chroot and bind mounts.
  177. bool is_root_inode = dir_inode.identifier() == dir_inode.fs().root_inode()->identifier();
  178. if (is_root_inode && !is_vfs_root(dir_inode.identifier()) && entry.name == "..") {
  179. auto mount = find_mount_for_guest(dir_inode);
  180. VERIFY(mount);
  181. VERIFY(mount->host());
  182. resolved_inode = mount->host()->identifier();
  183. }
  184. callback({ entry.name, resolved_inode, entry.file_type });
  185. return true;
  186. });
  187. }
  188. KResult VFS::utime(StringView path, Custody& base, time_t atime, time_t mtime)
  189. {
  190. auto custody_or_error = VFS::the().resolve_path(move(path), base);
  191. if (custody_or_error.is_error())
  192. return custody_or_error.error();
  193. auto& custody = *custody_or_error.value();
  194. auto& inode = custody.inode();
  195. auto current_process = Process::current();
  196. if (!current_process->is_superuser() && inode.metadata().uid != current_process->euid())
  197. return EACCES;
  198. if (custody.is_readonly())
  199. return EROFS;
  200. int error = inode.set_atime(atime);
  201. if (error < 0)
  202. return KResult((ErrnoCode)-error);
  203. error = inode.set_mtime(mtime);
  204. if (error < 0)
  205. return KResult((ErrnoCode)-error);
  206. return KSuccess;
  207. }
  208. KResultOr<InodeMetadata> VFS::lookup_metadata(StringView path, Custody& base, int options)
  209. {
  210. auto custody_or_error = resolve_path(path, base, nullptr, options);
  211. if (custody_or_error.is_error())
  212. return custody_or_error.error();
  213. return custody_or_error.value()->inode().metadata();
  214. }
  215. KResultOr<NonnullRefPtr<FileDescription>> VFS::open(StringView path, int options, mode_t mode, Custody& base, Optional<UidAndGid> owner)
  216. {
  217. if ((options & O_CREAT) && (options & O_DIRECTORY))
  218. return EINVAL;
  219. RefPtr<Custody> parent_custody;
  220. auto custody_or_error = resolve_path(path, base, &parent_custody, options);
  221. if (options & O_CREAT) {
  222. if (!parent_custody)
  223. return ENOENT;
  224. if (custody_or_error.is_error()) {
  225. if (custody_or_error.error() != -ENOENT)
  226. return custody_or_error.error();
  227. return create(path, options, mode, *parent_custody, move(owner));
  228. }
  229. if (options & O_EXCL)
  230. return EEXIST;
  231. }
  232. if (custody_or_error.is_error())
  233. return custody_or_error.error();
  234. auto& custody = *custody_or_error.value();
  235. auto& inode = custody.inode();
  236. auto metadata = inode.metadata();
  237. if ((options & O_DIRECTORY) && !metadata.is_directory())
  238. return ENOTDIR;
  239. bool should_truncate_file = false;
  240. auto current_process = Process::current();
  241. if ((options & O_RDONLY) && !metadata.may_read(*current_process))
  242. return EACCES;
  243. if (options & O_WRONLY) {
  244. if (!metadata.may_write(*current_process))
  245. return EACCES;
  246. if (metadata.is_directory())
  247. return EISDIR;
  248. should_truncate_file = options & O_TRUNC;
  249. }
  250. if (options & O_EXEC) {
  251. if (!metadata.may_execute(*current_process) || (custody.mount_flags() & MS_NOEXEC))
  252. return EACCES;
  253. }
  254. if (auto preopen_fd = inode.preopen_fd())
  255. return *preopen_fd;
  256. if (metadata.is_fifo()) {
  257. auto fifo = inode.fifo();
  258. if (options & O_WRONLY) {
  259. auto open_result = fifo->open_direction_blocking(FIFO::Direction::Writer);
  260. if (open_result.is_error())
  261. return open_result.error();
  262. auto& description = open_result.value();
  263. description->set_rw_mode(options);
  264. description->set_file_flags(options);
  265. description->set_original_inode({}, inode);
  266. return description;
  267. } else if (options & O_RDONLY) {
  268. auto open_result = fifo->open_direction_blocking(FIFO::Direction::Reader);
  269. if (open_result.is_error())
  270. return open_result.error();
  271. auto& description = open_result.value();
  272. description->set_rw_mode(options);
  273. description->set_file_flags(options);
  274. description->set_original_inode({}, inode);
  275. return description;
  276. }
  277. return EINVAL;
  278. }
  279. if (metadata.is_device()) {
  280. if (custody.mount_flags() & MS_NODEV)
  281. return EACCES;
  282. auto device = Device::get_device(metadata.major_device, metadata.minor_device);
  283. if (device == nullptr) {
  284. return ENODEV;
  285. }
  286. auto descriptor_or_error = device->open(options);
  287. if (descriptor_or_error.is_error())
  288. return descriptor_or_error.error();
  289. descriptor_or_error.value()->set_original_inode({}, inode);
  290. return descriptor_or_error;
  291. }
  292. // Check for read-only FS. Do this after handling preopen FD and devices,
  293. // but before modifying the inode in any way.
  294. if ((options & O_WRONLY) && custody.is_readonly())
  295. return EROFS;
  296. if (should_truncate_file) {
  297. KResult result = inode.truncate(0);
  298. if (result.is_error())
  299. return result;
  300. inode.set_mtime(kgettimeofday().to_truncated_seconds());
  301. }
  302. auto description = FileDescription::create(custody);
  303. if (!description.is_error()) {
  304. description.value()->set_rw_mode(options);
  305. description.value()->set_file_flags(options);
  306. }
  307. return description;
  308. }
  309. KResult VFS::mknod(StringView path, mode_t mode, dev_t dev, Custody& base)
  310. {
  311. if (!is_regular_file(mode) && !is_block_device(mode) && !is_character_device(mode) && !is_fifo(mode) && !is_socket(mode))
  312. return EINVAL;
  313. RefPtr<Custody> parent_custody;
  314. auto existing_file_or_error = resolve_path(path, base, &parent_custody);
  315. if (!existing_file_or_error.is_error())
  316. return EEXIST;
  317. if (!parent_custody)
  318. return ENOENT;
  319. if (existing_file_or_error.error() != -ENOENT)
  320. return existing_file_or_error.error();
  321. auto& parent_inode = parent_custody->inode();
  322. auto current_process = Process::current();
  323. if (!parent_inode.metadata().may_write(*current_process))
  324. return EACCES;
  325. if (parent_custody->is_readonly())
  326. return EROFS;
  327. LexicalPath p(path);
  328. dbgln("VFS::mknod: '{}' mode={} dev={} in {}", p.basename(), mode, dev, parent_inode.identifier());
  329. return parent_inode.create_child(p.basename(), mode, dev, current_process->euid(), current_process->egid()).result();
  330. }
  331. KResultOr<NonnullRefPtr<FileDescription>> VFS::create(StringView path, int options, mode_t mode, Custody& parent_custody, Optional<UidAndGid> owner)
  332. {
  333. LexicalPath p(path);
  334. auto result = validate_path_against_process_veil(String::formatted("{}/{}", parent_custody.absolute_path(), p.basename()), options);
  335. if (result.is_error())
  336. return result;
  337. if (!is_socket(mode) && !is_fifo(mode) && !is_block_device(mode) && !is_character_device(mode)) {
  338. // Turn it into a regular file. (This feels rather hackish.)
  339. mode |= 0100000;
  340. }
  341. auto& parent_inode = parent_custody.inode();
  342. auto current_process = Process::current();
  343. if (!parent_inode.metadata().may_write(*current_process))
  344. return EACCES;
  345. if (parent_custody.is_readonly())
  346. return EROFS;
  347. dbgln_if(VFS_DEBUG, "VFS::create: '{}' in {}", p.basename(), parent_inode.identifier());
  348. uid_t uid = owner.has_value() ? owner.value().uid : current_process->euid();
  349. gid_t gid = owner.has_value() ? owner.value().gid : current_process->egid();
  350. auto inode_or_error = parent_inode.create_child(p.basename(), mode, 0, uid, gid);
  351. if (inode_or_error.is_error())
  352. return inode_or_error.error();
  353. auto new_custody = Custody::create(&parent_custody, p.basename(), inode_or_error.value(), parent_custody.mount_flags());
  354. auto description = FileDescription::create(*new_custody);
  355. if (!description.is_error()) {
  356. description.value()->set_rw_mode(options);
  357. description.value()->set_file_flags(options);
  358. }
  359. return description;
  360. }
  361. KResult VFS::mkdir(StringView path, mode_t mode, Custody& base)
  362. {
  363. // Unlike in basically every other case, where it's only the last
  364. // path component (the one being created) that is allowed not to
  365. // exist, POSIX allows mkdir'ed path to have trailing slashes.
  366. // Let's handle that case by trimming any trailing slashes.
  367. while (path.length() > 1 && path.ends_with("/"))
  368. path = path.substring_view(0, path.length() - 1);
  369. RefPtr<Custody> parent_custody;
  370. auto result = resolve_path(path, base, &parent_custody);
  371. if (!result.is_error())
  372. return EEXIST;
  373. if (!parent_custody)
  374. return ENOENT;
  375. if (result.error() != -ENOENT)
  376. return result.error();
  377. auto& parent_inode = parent_custody->inode();
  378. auto current_process = Process::current();
  379. if (!parent_inode.metadata().may_write(*current_process))
  380. return EACCES;
  381. if (parent_custody->is_readonly())
  382. return EROFS;
  383. LexicalPath p(path);
  384. dbgln_if(VFS_DEBUG, "VFS::mkdir: '{}' in {}", p.basename(), parent_inode.identifier());
  385. return parent_inode.create_child(p.basename(), S_IFDIR | mode, 0, current_process->euid(), current_process->egid()).result();
  386. }
  387. KResult VFS::access(StringView path, int mode, Custody& base)
  388. {
  389. auto custody_or_error = resolve_path(path, base);
  390. if (custody_or_error.is_error())
  391. return custody_or_error.error();
  392. auto& custody = *custody_or_error.value();
  393. auto& inode = custody.inode();
  394. auto metadata = inode.metadata();
  395. auto current_process = Process::current();
  396. if (mode & R_OK) {
  397. if (!metadata.may_read(*current_process))
  398. return EACCES;
  399. }
  400. if (mode & W_OK) {
  401. if (!metadata.may_write(*current_process))
  402. return EACCES;
  403. if (custody.is_readonly())
  404. return EROFS;
  405. }
  406. if (mode & X_OK) {
  407. if (!metadata.may_execute(*current_process))
  408. return EACCES;
  409. }
  410. return KSuccess;
  411. }
  412. KResultOr<NonnullRefPtr<Custody>> VFS::open_directory(StringView path, Custody& base)
  413. {
  414. auto inode_or_error = resolve_path(path, base);
  415. if (inode_or_error.is_error())
  416. return inode_or_error.error();
  417. auto& custody = *inode_or_error.value();
  418. auto& inode = custody.inode();
  419. if (!inode.is_directory())
  420. return ENOTDIR;
  421. if (!inode.metadata().may_execute(*Process::current()))
  422. return EACCES;
  423. return custody;
  424. }
  425. KResult VFS::chmod(Custody& custody, mode_t mode)
  426. {
  427. auto& inode = custody.inode();
  428. auto current_process = Process::current();
  429. if (current_process->euid() != inode.metadata().uid && !current_process->is_superuser())
  430. return EPERM;
  431. if (custody.is_readonly())
  432. return EROFS;
  433. // Only change the permission bits.
  434. mode = (inode.mode() & ~07777u) | (mode & 07777u);
  435. return inode.chmod(mode);
  436. }
  437. KResult VFS::chmod(StringView path, mode_t mode, Custody& base)
  438. {
  439. auto custody_or_error = resolve_path(path, base);
  440. if (custody_or_error.is_error())
  441. return custody_or_error.error();
  442. auto& custody = *custody_or_error.value();
  443. return chmod(custody, mode);
  444. }
  445. KResult VFS::rename(StringView old_path, StringView new_path, Custody& base)
  446. {
  447. RefPtr<Custody> old_parent_custody;
  448. auto old_custody_or_error = resolve_path(old_path, base, &old_parent_custody, O_NOFOLLOW_NOERROR);
  449. if (old_custody_or_error.is_error())
  450. return old_custody_or_error.error();
  451. auto& old_custody = *old_custody_or_error.value();
  452. auto& old_inode = old_custody.inode();
  453. RefPtr<Custody> new_parent_custody;
  454. auto new_custody_or_error = resolve_path(new_path, base, &new_parent_custody);
  455. if (new_custody_or_error.is_error()) {
  456. if (new_custody_or_error.error() != -ENOENT || !new_parent_custody)
  457. return new_custody_or_error.error();
  458. }
  459. auto& old_parent_inode = old_parent_custody->inode();
  460. auto& new_parent_inode = new_parent_custody->inode();
  461. if (&old_parent_inode.fs() != &new_parent_inode.fs())
  462. return EXDEV;
  463. for (auto* new_ancestor = new_parent_custody.ptr(); new_ancestor; new_ancestor = new_ancestor->parent()) {
  464. if (&old_inode == &new_ancestor->inode())
  465. return EDIRINTOSELF;
  466. }
  467. auto current_process = Process::current();
  468. if (!new_parent_inode.metadata().may_write(*current_process))
  469. return EACCES;
  470. if (!old_parent_inode.metadata().may_write(*current_process))
  471. return EACCES;
  472. if (old_parent_inode.metadata().is_sticky()) {
  473. if (!current_process->is_superuser() && old_inode.metadata().uid != current_process->euid())
  474. return EACCES;
  475. }
  476. if (old_parent_custody->is_readonly() || new_parent_custody->is_readonly())
  477. return EROFS;
  478. auto new_basename = LexicalPath(new_path).basename();
  479. if (!new_custody_or_error.is_error()) {
  480. auto& new_custody = *new_custody_or_error.value();
  481. auto& new_inode = new_custody.inode();
  482. // FIXME: Is this really correct? Check what other systems do.
  483. if (&new_inode == &old_inode)
  484. return KSuccess;
  485. if (new_parent_inode.metadata().is_sticky()) {
  486. if (!current_process->is_superuser() && new_inode.metadata().uid != current_process->euid())
  487. return EACCES;
  488. }
  489. if (new_inode.is_directory() && !old_inode.is_directory())
  490. return EISDIR;
  491. auto result = new_parent_inode.remove_child(new_basename);
  492. if (result.is_error())
  493. return result;
  494. }
  495. auto result = new_parent_inode.add_child(old_inode, new_basename, old_inode.mode());
  496. if (result.is_error())
  497. return result;
  498. result = old_parent_inode.remove_child(LexicalPath(old_path).basename());
  499. if (result.is_error())
  500. return result;
  501. return KSuccess;
  502. }
  503. KResult VFS::chown(Custody& custody, uid_t a_uid, gid_t a_gid)
  504. {
  505. auto& inode = custody.inode();
  506. auto metadata = inode.metadata();
  507. auto current_process = Process::current();
  508. if (current_process->euid() != metadata.uid && !current_process->is_superuser())
  509. return EPERM;
  510. uid_t new_uid = metadata.uid;
  511. gid_t new_gid = metadata.gid;
  512. if (a_uid != (uid_t)-1) {
  513. if (current_process->euid() != a_uid && !current_process->is_superuser())
  514. return EPERM;
  515. new_uid = a_uid;
  516. }
  517. if (a_gid != (gid_t)-1) {
  518. if (!current_process->in_group(a_gid) && !current_process->is_superuser())
  519. return EPERM;
  520. new_gid = a_gid;
  521. }
  522. if (custody.is_readonly())
  523. return EROFS;
  524. dbgln("VFS::chown(): inode {} <- uid={} gid={}", inode.identifier(), new_uid, new_gid);
  525. if (metadata.is_setuid() || metadata.is_setgid()) {
  526. dbgln("VFS::chown(): Stripping SUID/SGID bits from {}", inode.identifier());
  527. auto result = inode.chmod(metadata.mode & ~(04000 | 02000));
  528. if (result.is_error())
  529. return result;
  530. }
  531. return inode.chown(new_uid, new_gid);
  532. }
  533. KResult VFS::chown(StringView path, uid_t a_uid, gid_t a_gid, Custody& base)
  534. {
  535. auto custody_or_error = resolve_path(path, base);
  536. if (custody_or_error.is_error())
  537. return custody_or_error.error();
  538. auto& custody = *custody_or_error.value();
  539. return chown(custody, a_uid, a_gid);
  540. }
  541. static bool hard_link_allowed(const Inode& inode)
  542. {
  543. auto metadata = inode.metadata();
  544. if (Process::current()->euid() == metadata.uid)
  545. return true;
  546. if (metadata.is_regular_file()
  547. && !metadata.is_setuid()
  548. && !(metadata.is_setgid() && metadata.mode & S_IXGRP)
  549. && metadata.may_write(*Process::current())) {
  550. return true;
  551. }
  552. return false;
  553. }
  554. KResult VFS::link(StringView old_path, StringView new_path, Custody& base)
  555. {
  556. auto old_custody_or_error = resolve_path(old_path, base);
  557. if (old_custody_or_error.is_error())
  558. return old_custody_or_error.error();
  559. auto& old_custody = *old_custody_or_error.value();
  560. auto& old_inode = old_custody.inode();
  561. RefPtr<Custody> parent_custody;
  562. auto new_custody_or_error = resolve_path(new_path, base, &parent_custody);
  563. if (!new_custody_or_error.is_error())
  564. return EEXIST;
  565. if (!parent_custody)
  566. return ENOENT;
  567. auto& parent_inode = parent_custody->inode();
  568. if (parent_inode.fsid() != old_inode.fsid())
  569. return EXDEV;
  570. if (!parent_inode.metadata().may_write(*Process::current()))
  571. return EACCES;
  572. if (old_inode.is_directory())
  573. return EPERM;
  574. if (parent_custody->is_readonly())
  575. return EROFS;
  576. if (!hard_link_allowed(old_inode))
  577. return EPERM;
  578. return parent_inode.add_child(old_inode, LexicalPath(new_path).basename(), old_inode.mode());
  579. }
  580. KResult VFS::unlink(StringView path, Custody& base)
  581. {
  582. RefPtr<Custody> parent_custody;
  583. auto custody_or_error = resolve_path(path, base, &parent_custody, O_NOFOLLOW_NOERROR | O_UNLINK_INTERNAL);
  584. if (custody_or_error.is_error())
  585. return custody_or_error.error();
  586. auto& custody = *custody_or_error.value();
  587. auto& inode = custody.inode();
  588. if (inode.is_directory())
  589. return EISDIR;
  590. // We have just checked that the inode is not a directory, and thus it's not
  591. // the root. So it should have a parent. Note that this would be invalidated
  592. // if we were to support bind-mounting regular files on top of the root.
  593. VERIFY(parent_custody);
  594. auto& parent_inode = parent_custody->inode();
  595. auto current_process = Process::current();
  596. if (!parent_inode.metadata().may_write(*current_process))
  597. return EACCES;
  598. if (parent_inode.metadata().is_sticky()) {
  599. if (!current_process->is_superuser() && inode.metadata().uid != current_process->euid())
  600. return EACCES;
  601. }
  602. if (parent_custody->is_readonly())
  603. return EROFS;
  604. auto result = parent_inode.remove_child(LexicalPath(path).basename());
  605. if (result.is_error())
  606. return result;
  607. return KSuccess;
  608. }
  609. KResult VFS::symlink(StringView target, StringView linkpath, Custody& base)
  610. {
  611. RefPtr<Custody> parent_custody;
  612. auto existing_custody_or_error = resolve_path(linkpath, base, &parent_custody);
  613. if (!existing_custody_or_error.is_error())
  614. return EEXIST;
  615. if (!parent_custody)
  616. return ENOENT;
  617. if (existing_custody_or_error.error() != -ENOENT)
  618. return existing_custody_or_error.error();
  619. auto& parent_inode = parent_custody->inode();
  620. auto current_process = Process::current();
  621. if (!parent_inode.metadata().may_write(*current_process))
  622. return EACCES;
  623. if (parent_custody->is_readonly())
  624. return EROFS;
  625. LexicalPath p(linkpath);
  626. dbgln("VFS::symlink: '{}' (-> '{}') in {}", p.basename(), target, parent_inode.identifier());
  627. auto inode_or_error = parent_inode.create_child(p.basename(), S_IFLNK | 0644, 0, current_process->euid(), current_process->egid());
  628. if (inode_or_error.is_error())
  629. return inode_or_error.error();
  630. auto& inode = inode_or_error.value();
  631. auto target_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((const u8*)target.characters_without_null_termination()));
  632. ssize_t nwritten = inode->write_bytes(0, target.length(), target_buffer, nullptr);
  633. if (nwritten < 0)
  634. return KResult((ErrnoCode)-nwritten);
  635. return KSuccess;
  636. }
  637. KResult VFS::rmdir(StringView path, Custody& base)
  638. {
  639. RefPtr<Custody> parent_custody;
  640. auto custody_or_error = resolve_path(path, base, &parent_custody);
  641. if (custody_or_error.is_error())
  642. return KResult(custody_or_error.error());
  643. auto& custody = *custody_or_error.value();
  644. auto& inode = custody.inode();
  645. // FIXME: We should return EINVAL if the last component of the path is "."
  646. // FIXME: We should return ENOTEMPTY if the last component of the path is ".."
  647. if (!inode.is_directory())
  648. return ENOTDIR;
  649. if (!parent_custody)
  650. return EBUSY;
  651. auto& parent_inode = parent_custody->inode();
  652. auto parent_metadata = parent_inode.metadata();
  653. if (!parent_metadata.may_write(*Process::current()))
  654. return EACCES;
  655. if (parent_metadata.is_sticky()) {
  656. if (!Process::current()->is_superuser() && inode.metadata().uid != Process::current()->euid())
  657. return EACCES;
  658. }
  659. KResultOr<size_t> dir_count_result = inode.directory_entry_count();
  660. if (dir_count_result.is_error())
  661. return dir_count_result.result();
  662. if (dir_count_result.value() != 2)
  663. return ENOTEMPTY;
  664. if (custody.is_readonly())
  665. return EROFS;
  666. auto result = inode.remove_child(".");
  667. if (result.is_error())
  668. return result;
  669. result = inode.remove_child("..");
  670. if (result.is_error())
  671. return result;
  672. return parent_inode.remove_child(LexicalPath(path).basename());
  673. }
  674. VFS::Mount::Mount(FS& guest_fs, Custody* host_custody, int flags)
  675. : m_guest(guest_fs.root_inode())
  676. , m_guest_fs(guest_fs)
  677. , m_host_custody(host_custody)
  678. , m_flags(flags)
  679. {
  680. }
  681. VFS::Mount::Mount(Inode& source, Custody& host_custody, int flags)
  682. : m_guest(source)
  683. , m_guest_fs(source.fs())
  684. , m_host_custody(host_custody)
  685. , m_flags(flags)
  686. {
  687. }
  688. String VFS::Mount::absolute_path() const
  689. {
  690. if (!m_host_custody)
  691. return "/";
  692. return m_host_custody->absolute_path();
  693. }
  694. Inode* VFS::Mount::host()
  695. {
  696. if (!m_host_custody)
  697. return nullptr;
  698. return &m_host_custody->inode();
  699. }
  700. const Inode* VFS::Mount::host() const
  701. {
  702. if (!m_host_custody)
  703. return nullptr;
  704. return &m_host_custody->inode();
  705. }
  706. void VFS::for_each_mount(Function<void(const Mount&)> callback) const
  707. {
  708. for (auto& mount : m_mounts) {
  709. callback(mount);
  710. }
  711. }
  712. void VFS::sync()
  713. {
  714. FS::sync();
  715. }
  716. Custody& VFS::root_custody()
  717. {
  718. if (!m_root_custody)
  719. m_root_custody = Custody::create(nullptr, "", *m_root_inode, root_mount_flags);
  720. return *m_root_custody;
  721. }
  722. const UnveilNode* VFS::find_matching_unveiled_path(StringView path)
  723. {
  724. auto& unveil_root = Process::current()->unveiled_paths();
  725. if (unveil_root.is_empty())
  726. return nullptr;
  727. LexicalPath lexical_path { path };
  728. auto& path_parts = lexical_path.parts();
  729. auto& last_matching_node = unveil_root.traverse_until_last_accessible_node(path_parts.begin(), path_parts.end());
  730. return &last_matching_node;
  731. }
  732. KResult VFS::validate_path_against_process_veil(StringView path, int options)
  733. {
  734. if (Process::current()->veil_state() == VeilState::None)
  735. return KSuccess;
  736. if (path == "/usr/lib/Loader.so")
  737. return KSuccess;
  738. // FIXME: Figure out a nicer way to do this.
  739. if (String(path).contains("/.."))
  740. return EINVAL;
  741. auto* unveiled_path = find_matching_unveiled_path(path);
  742. if (!unveiled_path) {
  743. dbgln("Rejecting path '{}' since it hasn't been unveiled.", path);
  744. dump_backtrace();
  745. return ENOENT;
  746. }
  747. if (options & O_CREAT) {
  748. if (!(unveiled_path->permissions() & UnveilAccess::CreateOrRemove)) {
  749. dbgln("Rejecting path '{}' since it hasn't been unveiled with 'c' permission.", path);
  750. dump_backtrace();
  751. return EACCES;
  752. }
  753. }
  754. if (options & O_UNLINK_INTERNAL) {
  755. if (!(unveiled_path->permissions() & UnveilAccess::CreateOrRemove)) {
  756. dbgln("Rejecting path '{}' for unlink since it hasn't been unveiled with 'c' permission.", path);
  757. dump_backtrace();
  758. return EACCES;
  759. }
  760. return KSuccess;
  761. }
  762. if (options & O_RDONLY) {
  763. if (options & O_DIRECTORY) {
  764. if (!(unveiled_path->permissions() & (UnveilAccess::Read | UnveilAccess::Browse))) {
  765. dbgln("Rejecting path '{}' since it hasn't been unveiled with 'r' or 'b' permissions.", path);
  766. dump_backtrace();
  767. return EACCES;
  768. }
  769. } else {
  770. if (!(unveiled_path->permissions() & UnveilAccess::Read)) {
  771. dbgln("Rejecting path '{}' since it hasn't been unveiled with 'r' permission.", path);
  772. dump_backtrace();
  773. return EACCES;
  774. }
  775. }
  776. }
  777. if (options & O_WRONLY) {
  778. if (!(unveiled_path->permissions() & UnveilAccess::Write)) {
  779. dbgln("Rejecting path '{}' since it hasn't been unveiled with 'w' permission.", path);
  780. dump_backtrace();
  781. return EACCES;
  782. }
  783. }
  784. if (options & O_EXEC) {
  785. if (!(unveiled_path->permissions() & UnveilAccess::Execute)) {
  786. dbgln("Rejecting path '{}' since it hasn't been unveiled with 'x' permission.", path);
  787. dump_backtrace();
  788. return EACCES;
  789. }
  790. }
  791. return KSuccess;
  792. }
  793. KResultOr<NonnullRefPtr<Custody>> VFS::resolve_path(StringView path, Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level)
  794. {
  795. auto custody_or_error = resolve_path_without_veil(path, base, out_parent, options, symlink_recursion_level);
  796. if (custody_or_error.is_error())
  797. return custody_or_error.error();
  798. auto& custody = custody_or_error.value();
  799. auto result = validate_path_against_process_veil(custody->absolute_path(), options);
  800. if (result.is_error())
  801. return result;
  802. return custody;
  803. }
  804. static bool safe_to_follow_symlink(const Inode& inode, const InodeMetadata& parent_metadata)
  805. {
  806. auto metadata = inode.metadata();
  807. if (Process::current()->euid() == metadata.uid)
  808. return true;
  809. if (!(parent_metadata.is_sticky() && parent_metadata.mode & S_IWOTH))
  810. return true;
  811. if (metadata.uid == parent_metadata.uid)
  812. return true;
  813. return false;
  814. }
  815. KResultOr<NonnullRefPtr<Custody>> VFS::resolve_path_without_veil(StringView path, Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level)
  816. {
  817. if (symlink_recursion_level >= symlink_recursion_limit)
  818. return ELOOP;
  819. if (path.is_empty())
  820. return EINVAL;
  821. auto parts = path.split_view('/', true);
  822. auto current_process = Process::current();
  823. auto& current_root = current_process->root_directory();
  824. NonnullRefPtr<Custody> custody = path[0] == '/' ? current_root : base;
  825. for (size_t i = 0; i < parts.size(); ++i) {
  826. Custody& parent = custody;
  827. auto parent_metadata = parent.inode().metadata();
  828. if (!parent_metadata.is_directory())
  829. return ENOTDIR;
  830. // Ensure the current user is allowed to resolve paths inside this directory.
  831. if (!parent_metadata.may_execute(*current_process))
  832. return EACCES;
  833. auto& part = parts[i];
  834. bool have_more_parts = i + 1 < parts.size();
  835. if (part == "..") {
  836. // If we encounter a "..", take a step back, but don't go beyond the root.
  837. if (custody->parent())
  838. custody = *custody->parent();
  839. continue;
  840. } else if (part == "." || part.is_empty()) {
  841. continue;
  842. }
  843. // Okay, let's look up this part.
  844. auto child_inode = parent.inode().lookup(part);
  845. if (!child_inode) {
  846. if (out_parent) {
  847. // ENOENT with a non-null parent custody signals to caller that
  848. // we found the immediate parent of the file, but the file itself
  849. // does not exist yet.
  850. *out_parent = have_more_parts ? nullptr : &parent;
  851. }
  852. return ENOENT;
  853. }
  854. int mount_flags_for_child = parent.mount_flags();
  855. // See if there's something mounted on the child; in that case
  856. // we would need to return the guest inode, not the host inode.
  857. if (auto mount = find_mount_for_host(*child_inode)) {
  858. child_inode = mount->guest();
  859. mount_flags_for_child = mount->flags();
  860. }
  861. custody = Custody::create(&parent, part, *child_inode, mount_flags_for_child);
  862. if (child_inode->metadata().is_symlink()) {
  863. if (!have_more_parts) {
  864. if (options & O_NOFOLLOW)
  865. return ELOOP;
  866. if (options & O_NOFOLLOW_NOERROR)
  867. break;
  868. }
  869. if (!safe_to_follow_symlink(*child_inode, parent_metadata))
  870. return EACCES;
  871. auto result = validate_path_against_process_veil(custody->absolute_path(), options);
  872. if (result.is_error())
  873. return result;
  874. auto symlink_target = child_inode->resolve_as_link(parent, out_parent, options, symlink_recursion_level + 1);
  875. if (symlink_target.is_error() || !have_more_parts)
  876. return symlink_target;
  877. // Now, resolve the remaining path relative to the symlink target.
  878. // We prepend a "." to it to ensure that it's not empty and that
  879. // any initial slashes it might have get interpreted properly.
  880. StringBuilder remaining_path;
  881. remaining_path.append('.');
  882. remaining_path.append(path.substring_view_starting_after_substring(part));
  883. return resolve_path_without_veil(remaining_path.to_string(), *symlink_target.value(), out_parent, options, symlink_recursion_level + 1);
  884. }
  885. }
  886. if (out_parent)
  887. *out_parent = custody->parent();
  888. return custody;
  889. }
  890. }