diff --git a/repos/libports/src/lib/libc/execve.cc b/repos/libports/src/lib/libc/execve.cc index e00149e6d9..55913b7158 100644 --- a/repos/libports/src/lib/libc/execve.cc +++ b/repos/libports/src/lib/libc/execve.cc @@ -372,9 +372,7 @@ extern "C" int execve(char const *filename, for (unsigned i = 0; i < MAX_INTERPRETER_NESTING_LEVELS; i++) { - try { - Libc::resolve_symlinks(path.string(), resolved_path); } - catch (Libc::Symlink_resolve_error) { + if (Libc::resolve_symlinks(path.string(), resolved_path).failed()) { warning("execve: executable binary '", filename, "' does not exist"); return Libc::Errno(ENOENT); } diff --git a/repos/libports/src/lib/libc/file_operations.cc b/repos/libports/src/lib/libc/file_operations.cc index ac4c4c0a21..466f81b4eb 100644 --- a/repos/libports/src/lib/libc/file_operations.cc +++ b/repos/libports/src/lib/libc/file_operations.cc @@ -41,6 +41,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -104,7 +105,7 @@ typedef Token Path_element_token; /** * Resolve symbolic links in a given absolute path */ -void Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path) +Symlink_resolve_result Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path) { char path_element[PATH_MAX]; char symlink_target[PATH_MAX]; @@ -118,7 +119,7 @@ void Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path) do { if (follow_count++ == FOLLOW_LIMIT) { errno = ELOOP; - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } current_iteration_working_path = next_iteration_working_path; @@ -140,7 +141,7 @@ void Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path) next_iteration_working_path.append_element(path_element); } catch (Path_base::Path_too_long) { errno = ENAMETOOLONG; - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } /* @@ -152,14 +153,14 @@ void Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path) int res; FNAME_FUNC_WRAPPER_GENERIC(res = , stat, next_iteration_working_path.base(), &stat_buf); if (res == -1) { - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } if (S_ISLNK(stat_buf.st_mode)) { FNAME_FUNC_WRAPPER_GENERIC(res = , readlink, next_iteration_working_path.base(), symlink_target, sizeof(symlink_target) - 1); if (res < 1) - throw Symlink_resolve_error(); + return Symlink_resolve_error(); /* zero terminate target */ symlink_target[res] = 0; @@ -174,7 +175,7 @@ void Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path) next_iteration_working_path.append_element(symlink_target); } catch (Path_base::Path_too_long) { errno = ENAMETOOLONG; - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } } symlink_resolved_in_this_iteration = true; @@ -188,10 +189,12 @@ void Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path) resolved_path = next_iteration_working_path; resolved_path.remove_trailing('/'); + + return Symlinks_resolved_ok(); } -static void resolve_symlinks_except_last_element(char const *path, Absolute_path &resolved_path) +static Symlink_resolve_result resolve_symlinks_except_last_element(char const *path, Absolute_path &resolved_path) { Absolute_path absolute_path_without_last_element(path, cwd().base()); absolute_path_without_last_element.strip_last_element(); @@ -205,8 +208,10 @@ static void resolve_symlinks_except_last_element(char const *path, Absolute_path resolved_path.append_element(absolute_path_last_element.base()); } catch (Path_base::Path_too_long) { errno = ENAMETOOLONG; - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } + + return Symlinks_resolved_ok(); } @@ -222,14 +227,14 @@ extern "C" int access(const char *path, int amode) if (path[0] == '\0') return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks(path, resolved_path); - FNAME_FUNC_WRAPPER(access, resolved_path.base(), amode); - } catch (Symlink_resolve_error) { + Absolute_path resolved_path; + + if (resolve_symlinks(path, resolved_path).failed()) { errno = ENOENT; return -1; } + + FNAME_FUNC_WRAPPER(access, resolved_path.base(), amode); } @@ -408,14 +413,13 @@ extern "C" int lstat(const char *path, struct stat *buf) if (path[0] == '\0') return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks_except_last_element(path, resolved_path); - resolved_path.remove_trailing('/'); - FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf); - } catch (Symlink_resolve_error) { + Absolute_path resolved_path; + + if (resolve_symlinks_except_last_element(path, resolved_path).failed()) return -1; - } + + resolved_path.remove_trailing('/'); + FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf); } @@ -427,14 +431,13 @@ extern "C" int mkdir(const char *path, mode_t mode) if (path[0] == '\0') return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks_except_last_element(path, resolved_path); - resolved_path.remove_trailing('/'); - FNAME_FUNC_WRAPPER(mkdir, resolved_path.base(), mode); - } catch(Symlink_resolve_error) { + Absolute_path resolved_path; + + if (resolve_symlinks_except_last_element(path, resolved_path).failed()) return -1; - } + + resolved_path.remove_trailing('/'); + FNAME_FUNC_WRAPPER(mkdir, resolved_path.base(), mode); } @@ -550,17 +553,12 @@ __SYS_(int, open, (const char *pathname, int flags, ...), Plugin *plugin; File_descriptor *new_fdo; - try { - resolve_symlinks_except_last_element(pathname, resolved_path); - } catch (Symlink_resolve_error) { + if (resolve_symlinks_except_last_element(pathname, resolved_path).failed()) return -1; - } if (!(flags & O_NOFOLLOW)) { /* resolve last element */ - try { - resolve_symlinks(resolved_path.base(), resolved_path); - } catch (Symlink_resolve_error) { + if (resolve_symlinks(resolved_path.base(), resolved_path).failed()) { if (errno == ENOENT) { if (!(flags & O_CREAT)) return -1; @@ -671,13 +669,12 @@ extern "C" ssize_t readlink(const char *path, char *buf, ::size_t bufsiz) if (path[0] == '\0') return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks_except_last_element(path, resolved_path); - FNAME_FUNC_WRAPPER(readlink, resolved_path.base(), buf, bufsiz); - } catch(Symlink_resolve_error) { + Absolute_path resolved_path; + + if (resolve_symlinks_except_last_element(path, resolved_path).failed()) return -1; - } + + FNAME_FUNC_WRAPPER(readlink, resolved_path.base(), buf, bufsiz); } @@ -689,18 +686,18 @@ extern "C" int rename(const char *oldpath, const char *newpath) if ((oldpath[0] == '\0') || (newpath[0] == '\0')) return Errno(ENOENT); - try { - Absolute_path resolved_oldpath, resolved_newpath; - resolve_symlinks_except_last_element(oldpath, resolved_oldpath); - resolve_symlinks_except_last_element(newpath, resolved_newpath); + Absolute_path resolved_oldpath, resolved_newpath; - resolved_oldpath.remove_trailing('/'); - resolved_newpath.remove_trailing('/'); - - FNAME_FUNC_WRAPPER(rename, resolved_oldpath.base(), resolved_newpath.base()); - } catch(Symlink_resolve_error) { + if (resolve_symlinks_except_last_element(oldpath, resolved_oldpath).failed()) return -1; - } + + if (resolve_symlinks_except_last_element(newpath, resolved_newpath).failed()) + return -1; + + resolved_oldpath.remove_trailing('/'); + resolved_newpath.remove_trailing('/'); + + FNAME_FUNC_WRAPPER(rename, resolved_oldpath.base(), resolved_newpath.base()); } @@ -712,25 +709,24 @@ extern "C" int rmdir(const char *path) if (path[0] == '\0') return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks_except_last_element(path, resolved_path); - resolved_path.remove_trailing('/'); + Absolute_path resolved_path; - struct stat stat_buf { }; + if (resolve_symlinks_except_last_element(path, resolved_path).failed()) + return -1; - if (stat(resolved_path.base(), &stat_buf) == -1) - return -1; + resolved_path.remove_trailing('/'); - if (!S_ISDIR(stat_buf.st_mode)) { - errno = ENOTDIR; - return -1; - } + struct stat stat_buf { }; - FNAME_FUNC_WRAPPER(rmdir, resolved_path.base()); - } catch(Symlink_resolve_error) { + if (stat(resolved_path.base(), &stat_buf) == -1) + return -1; + + if (!S_ISDIR(stat_buf.st_mode)) { + errno = ENOTDIR; return -1; } + + FNAME_FUNC_WRAPPER(rmdir, resolved_path.base()); } @@ -742,14 +738,13 @@ extern "C" int stat(const char *path, struct stat *buf) if (path[0] == '\0') return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks(path, resolved_path); - resolved_path.remove_trailing('/'); - FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf); - } catch(Symlink_resolve_error) { + Absolute_path resolved_path; + + if (resolve_symlinks(path, resolved_path).failed()) return -1; - } + + resolved_path.remove_trailing('/'); + FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf); } @@ -761,13 +756,12 @@ extern "C" int symlink(const char *oldpath, const char *newpath) if ((oldpath[0] == '\0') || (newpath[0] == '\0')) return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks_except_last_element(newpath, resolved_path); - FNAME_FUNC_WRAPPER(symlink, oldpath, resolved_path.base()); - } catch(Symlink_resolve_error) { + Absolute_path resolved_path; + + if (resolve_symlinks_except_last_element(newpath, resolved_path).failed()) return -1; - } + + FNAME_FUNC_WRAPPER(symlink, oldpath, resolved_path.base()); } @@ -779,13 +773,12 @@ extern "C" int unlink(const char *path) if (path[0] == '\0') return Errno(ENOENT); - try { - Absolute_path resolved_path; - resolve_symlinks_except_last_element(path, resolved_path); - FNAME_FUNC_WRAPPER(unlink, resolved_path.base()); - } catch(Symlink_resolve_error) { + Absolute_path resolved_path; + + if (resolve_symlinks_except_last_element(path, resolved_path).failed()) return -1; - } + + FNAME_FUNC_WRAPPER(unlink, resolved_path.base()); } diff --git a/repos/libports/src/lib/libc/internal/file_operations.h b/repos/libports/src/lib/libc/internal/file_operations.h index 15110b60aa..cce9b93565 100644 --- a/repos/libports/src/lib/libc/internal/file_operations.h +++ b/repos/libports/src/lib/libc/internal/file_operations.h @@ -28,7 +28,12 @@ namespace Libc { typedef Genode::Path Absolute_path; - void resolve_symlinks(char const *path, Absolute_path &resolved_path); + struct Symlinks_resolved_ok { }; + struct Symlink_resolve_error { }; + using Symlink_resolve_result = Attempt; + + Symlink_resolve_result resolve_symlinks(char const *path, + Absolute_path &resolved_path); } #endif /* _LIBC__INTERNAL__FILE_OPERATIONS_H_ */ diff --git a/repos/libports/src/lib/libc/internal/plugin.h b/repos/libports/src/lib/libc/internal/plugin.h index d26513d190..9c63ee8cac 100644 --- a/repos/libports/src/lib/libc/internal/plugin.h +++ b/repos/libports/src/lib/libc/internal/plugin.h @@ -35,10 +35,6 @@ namespace Libc { typedef Genode::Path Absolute_path; - class Symlink_resolve_error : Genode::Exception { }; - - void resolve_symlinks(char const *path, Absolute_path &resolved_path); - class Plugin : public List::Element { protected: diff --git a/repos/libports/src/lib/libc/kernel.cc b/repos/libports/src/lib/libc/kernel.cc index 0f16d90ccc..f2af848e2b 100644 --- a/repos/libports/src/lib/libc/kernel.cc +++ b/repos/libports/src/lib/libc/kernel.cc @@ -15,6 +15,7 @@ /* libc-internal includes */ #include +#include Libc::Kernel * Libc::Kernel::_kernel_ptr; @@ -84,7 +85,8 @@ void Libc::Kernel::_init_file_descriptors() } diag_guard { *this }; - auto resolve_symlinks = [&] (Absolute_path next_iteration_working_path, Absolute_path &resolved_path) + auto resolve_symlinks = [&] (Absolute_path next_iteration_working_path, + Absolute_path &resolved_path) -> Symlink_resolve_result { char path_element[PATH_MAX]; char symlink_target[PATH_MAX]; @@ -97,7 +99,7 @@ void Libc::Kernel::_init_file_descriptors() do { if (follow_count++ == FOLLOW_LIMIT) { errno = ELOOP; - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } current_iteration_working_path = next_iteration_working_path; @@ -119,7 +121,7 @@ void Libc::Kernel::_init_file_descriptors() next_iteration_working_path.append_element(path_element); } catch (Path_base::Path_too_long) { errno = ENAMETOOLONG; - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } /* @@ -130,13 +132,13 @@ void Libc::Kernel::_init_file_descriptors() struct stat stat_buf; int res = _vfs.stat_from_kernel(next_iteration_working_path.base(), &stat_buf); if (res == -1) { - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } if (S_ISLNK(stat_buf.st_mode)) { res = readlink(next_iteration_working_path.base(), symlink_target, sizeof(symlink_target) - 1); if (res < 1) - throw Symlink_resolve_error(); + return Symlink_resolve_error(); /* zero terminate target */ symlink_target[res] = 0; @@ -151,7 +153,7 @@ void Libc::Kernel::_init_file_descriptors() next_iteration_working_path.append_element(symlink_target); } catch (Path_base::Path_too_long) { errno = ENAMETOOLONG; - throw Symlink_resolve_error(); + return Symlink_resolve_error(); } } symlink_resolved_in_this_iteration = true; @@ -165,21 +167,28 @@ void Libc::Kernel::_init_file_descriptors() resolved_path = next_iteration_working_path; resolved_path.remove_trailing('/'); + + return Symlinks_resolved_ok(); }; typedef String Path; - auto resolve_absolute_path = [&] (Path const &path) + struct Absolute_path_resolved_ok { }; + struct Absolute_path_resolve_error { }; + using Absolute_path_resolve_result = Attempt; + + auto resolve_absolute_path = [&] (Path const &path, Absolute_path &abs_path) -> Absolute_path_resolve_result { - Absolute_path abs_path { }; Absolute_path abs_dir(path.string(), _cwd.base()); abs_dir.strip_last_element(); Absolute_path dir_entry(path.string(), _cwd.base()); dir_entry.keep_only_last_element(); try { - resolve_symlinks(abs_dir, abs_path); + if (resolve_symlinks(abs_dir, abs_path).failed()) + return Absolute_path_resolve_error(); abs_path.append_element(dir_entry.string()); - return abs_path; - } catch (Path_base::Path_too_long) { return Absolute_path(); } + return Absolute_path_resolved_ok(); + } catch (Path_base::Path_too_long) { return Absolute_path_resolve_error(); } }; auto init_fd = [&] (Xml_node const &node, char const *attr, @@ -189,55 +198,55 @@ void Libc::Kernel::_init_file_descriptors() return; Path const attr_value { node.attribute_value(attr, Path()) }; - try { - Absolute_path const path { resolve_absolute_path(attr_value) }; - struct stat out_stat { }; - if (_vfs.stat_from_kernel(path.string(), &out_stat) != 0) { - warning("failed to call 'stat' on ", path); - diag_guard.show = true; - return; - } + Absolute_path path { }; - File_descriptor *fd = - _vfs.open_from_kernel(path.string(), flags, libc_fd); - - if (!fd) - return; - - if (fd->libc_fd != libc_fd) { - error("could not allocate fd ",libc_fd," for ",path,", " - "got fd ",fd->libc_fd); - _vfs.close_from_kernel(fd); - diag_guard.show = true; - return; - } - - fd->cloexec = node.attribute_value("cloexec", false); - - /* - * We need to manually register the path. Normally this is done - * by '_open'. But we call the local 'open' function directly - * because we want to explicitly specify the libc fd ID. - */ - if (fd->fd_path) - warning("may leak former FD path memory"); - - { - char *dst = (char *)_heap.alloc(path.max_len()); - copy_cstring(dst, path.string(), path.max_len()); - fd->fd_path = dst; - } - - ::off_t const seek = node.attribute_value("seek", 0ULL); - if (seek) - _vfs.lseek_from_kernel(fd, seek); - - } catch (Symlink_resolve_error) { - warning("failed to resolve path for ", attr_value); + if (resolve_absolute_path(attr_value, path).failed()) { + warning("failed to resolve path for ", path); diag_guard.show = true; return; } + + struct stat out_stat { }; + if (_vfs.stat_from_kernel(path.string(), &out_stat) != 0) { + warning("failed to call 'stat' on ", path); + diag_guard.show = true; + return; + } + + File_descriptor *fd = + _vfs.open_from_kernel(path.string(), flags, libc_fd); + + if (!fd) + return; + + if (fd->libc_fd != libc_fd) { + error("could not allocate fd ",libc_fd," for ",path,", " + "got fd ",fd->libc_fd); + _vfs.close_from_kernel(fd); + diag_guard.show = true; + return; + } + + fd->cloexec = node.attribute_value("cloexec", false); + + /* + * We need to manually register the path. Normally this is done + * by '_open'. But we call the local 'open' function directly + * because we want to explicitly specify the libc fd ID. + */ + if (fd->fd_path) + warning("may leak former FD path memory"); + + { + char *dst = (char *)_heap.alloc(path.max_len()); + copy_cstring(dst, path.string(), path.max_len()); + fd->fd_path = dst; + } + + ::off_t const seek = node.attribute_value("seek", 0ULL); + if (seek) + _vfs.lseek_from_kernel(fd, seek); }; if (_vfs.root_dir_has_dirents()) {