libc: remove 'Symlink_resolve_error' exception

Issue #5198
This commit is contained in:
Christian Prochaska 2024-05-07 22:53:31 +02:00
parent bfddf08f75
commit a59f73f7d3
5 changed files with 146 additions and 145 deletions

View File

@ -372,9 +372,7 @@ extern "C" int execve(char const *filename,
for (unsigned i = 0; i < MAX_INTERPRETER_NESTING_LEVELS; i++) { for (unsigned i = 0; i < MAX_INTERPRETER_NESTING_LEVELS; i++) {
try { if (Libc::resolve_symlinks(path.string(), resolved_path).failed()) {
Libc::resolve_symlinks(path.string(), resolved_path); }
catch (Libc::Symlink_resolve_error) {
warning("execve: executable binary '", filename, "' does not exist"); warning("execve: executable binary '", filename, "' does not exist");
return Libc::Errno(ENOENT); return Libc::Errno(ENOENT);
} }

View File

@ -41,6 +41,7 @@ extern "C" {
#include <internal/plugin_registry.h> #include <internal/plugin_registry.h>
#include <internal/plugin.h> #include <internal/plugin.h>
#include <internal/file.h> #include <internal/file.h>
#include <internal/file_operations.h>
#include <internal/mem_alloc.h> #include <internal/mem_alloc.h>
#include <internal/mmap_registry.h> #include <internal/mmap_registry.h>
#include <internal/errno.h> #include <internal/errno.h>
@ -104,7 +105,7 @@ typedef Token<Vfs::Scanner_policy_path_element> Path_element_token;
/** /**
* Resolve symbolic links in a given absolute path * 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 path_element[PATH_MAX];
char symlink_target[PATH_MAX]; char symlink_target[PATH_MAX];
@ -118,7 +119,7 @@ void Libc::resolve_symlinks(char const *path, Absolute_path &resolved_path)
do { do {
if (follow_count++ == FOLLOW_LIMIT) { if (follow_count++ == FOLLOW_LIMIT) {
errno = ELOOP; errno = ELOOP;
throw Symlink_resolve_error(); return Symlink_resolve_error();
} }
current_iteration_working_path = next_iteration_working_path; 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); next_iteration_working_path.append_element(path_element);
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
errno = ENAMETOOLONG; 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; int res;
FNAME_FUNC_WRAPPER_GENERIC(res = , stat, next_iteration_working_path.base(), &stat_buf); FNAME_FUNC_WRAPPER_GENERIC(res = , stat, next_iteration_working_path.base(), &stat_buf);
if (res == -1) { if (res == -1) {
throw Symlink_resolve_error(); return Symlink_resolve_error();
} }
if (S_ISLNK(stat_buf.st_mode)) { if (S_ISLNK(stat_buf.st_mode)) {
FNAME_FUNC_WRAPPER_GENERIC(res = , readlink, FNAME_FUNC_WRAPPER_GENERIC(res = , readlink,
next_iteration_working_path.base(), next_iteration_working_path.base(),
symlink_target, sizeof(symlink_target) - 1); symlink_target, sizeof(symlink_target) - 1);
if (res < 1) if (res < 1)
throw Symlink_resolve_error(); return Symlink_resolve_error();
/* zero terminate target */ /* zero terminate target */
symlink_target[res] = 0; 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); next_iteration_working_path.append_element(symlink_target);
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
throw Symlink_resolve_error(); return Symlink_resolve_error();
} }
} }
symlink_resolved_in_this_iteration = true; 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 = next_iteration_working_path;
resolved_path.remove_trailing('/'); 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 absolute_path_without_last_element(path, cwd().base());
absolute_path_without_last_element.strip_last_element(); 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()); resolved_path.append_element(absolute_path_last_element.base());
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
errno = ENAMETOOLONG; 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') if (path[0] == '\0')
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks(path, resolved_path);
FNAME_FUNC_WRAPPER(access, resolved_path.base(), amode); if (resolve_symlinks(path, resolved_path).failed()) {
} catch (Symlink_resolve_error) {
errno = ENOENT; errno = ENOENT;
return -1; 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') if (path[0] == '\0')
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks_except_last_element(path, resolved_path);
if (resolve_symlinks_except_last_element(path, resolved_path).failed())
return -1;
resolved_path.remove_trailing('/'); resolved_path.remove_trailing('/');
FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf); FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf);
} catch (Symlink_resolve_error) {
return -1;
}
} }
@ -427,14 +431,13 @@ extern "C" int mkdir(const char *path, mode_t mode)
if (path[0] == '\0') if (path[0] == '\0')
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks_except_last_element(path, resolved_path);
if (resolve_symlinks_except_last_element(path, resolved_path).failed())
return -1;
resolved_path.remove_trailing('/'); resolved_path.remove_trailing('/');
FNAME_FUNC_WRAPPER(mkdir, resolved_path.base(), mode); FNAME_FUNC_WRAPPER(mkdir, resolved_path.base(), mode);
} catch(Symlink_resolve_error) {
return -1;
}
} }
@ -550,17 +553,12 @@ __SYS_(int, open, (const char *pathname, int flags, ...),
Plugin *plugin; Plugin *plugin;
File_descriptor *new_fdo; File_descriptor *new_fdo;
try { if (resolve_symlinks_except_last_element(pathname, resolved_path).failed())
resolve_symlinks_except_last_element(pathname, resolved_path);
} catch (Symlink_resolve_error) {
return -1; return -1;
}
if (!(flags & O_NOFOLLOW)) { if (!(flags & O_NOFOLLOW)) {
/* resolve last element */ /* resolve last element */
try { if (resolve_symlinks(resolved_path.base(), resolved_path).failed()) {
resolve_symlinks(resolved_path.base(), resolved_path);
} catch (Symlink_resolve_error) {
if (errno == ENOENT) { if (errno == ENOENT) {
if (!(flags & O_CREAT)) if (!(flags & O_CREAT))
return -1; return -1;
@ -671,13 +669,12 @@ extern "C" ssize_t readlink(const char *path, char *buf, ::size_t bufsiz)
if (path[0] == '\0') if (path[0] == '\0')
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks_except_last_element(path, resolved_path);
FNAME_FUNC_WRAPPER(readlink, resolved_path.base(), buf, bufsiz); if (resolve_symlinks_except_last_element(path, resolved_path).failed())
} catch(Symlink_resolve_error) {
return -1; 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')) if ((oldpath[0] == '\0') || (newpath[0] == '\0'))
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_oldpath, resolved_newpath; Absolute_path resolved_oldpath, resolved_newpath;
resolve_symlinks_except_last_element(oldpath, resolved_oldpath);
resolve_symlinks_except_last_element(newpath, resolved_newpath); 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_oldpath.remove_trailing('/');
resolved_newpath.remove_trailing('/'); resolved_newpath.remove_trailing('/');
FNAME_FUNC_WRAPPER(rename, resolved_oldpath.base(), resolved_newpath.base()); FNAME_FUNC_WRAPPER(rename, resolved_oldpath.base(), resolved_newpath.base());
} catch(Symlink_resolve_error) {
return -1;
}
} }
@ -712,9 +709,11 @@ extern "C" int rmdir(const char *path)
if (path[0] == '\0') if (path[0] == '\0')
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks_except_last_element(path, resolved_path);
if (resolve_symlinks_except_last_element(path, resolved_path).failed())
return -1;
resolved_path.remove_trailing('/'); resolved_path.remove_trailing('/');
struct stat stat_buf { }; struct stat stat_buf { };
@ -728,9 +727,6 @@ extern "C" int rmdir(const char *path)
} }
FNAME_FUNC_WRAPPER(rmdir, resolved_path.base()); FNAME_FUNC_WRAPPER(rmdir, resolved_path.base());
} catch(Symlink_resolve_error) {
return -1;
}
} }
@ -742,14 +738,13 @@ extern "C" int stat(const char *path, struct stat *buf)
if (path[0] == '\0') if (path[0] == '\0')
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks(path, resolved_path);
if (resolve_symlinks(path, resolved_path).failed())
return -1;
resolved_path.remove_trailing('/'); resolved_path.remove_trailing('/');
FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf); FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf);
} catch(Symlink_resolve_error) {
return -1;
}
} }
@ -761,13 +756,12 @@ extern "C" int symlink(const char *oldpath, const char *newpath)
if ((oldpath[0] == '\0') || (newpath[0] == '\0')) if ((oldpath[0] == '\0') || (newpath[0] == '\0'))
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks_except_last_element(newpath, resolved_path);
FNAME_FUNC_WRAPPER(symlink, oldpath, resolved_path.base()); if (resolve_symlinks_except_last_element(newpath, resolved_path).failed())
} catch(Symlink_resolve_error) {
return -1; 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') if (path[0] == '\0')
return Errno(ENOENT); return Errno(ENOENT);
try {
Absolute_path resolved_path; Absolute_path resolved_path;
resolve_symlinks_except_last_element(path, resolved_path);
FNAME_FUNC_WRAPPER(unlink, resolved_path.base()); if (resolve_symlinks_except_last_element(path, resolved_path).failed())
} catch(Symlink_resolve_error) {
return -1; return -1;
}
FNAME_FUNC_WRAPPER(unlink, resolved_path.base());
} }

View File

@ -28,7 +28,12 @@ namespace Libc {
typedef Genode::Path<PATH_MAX> Absolute_path; typedef Genode::Path<PATH_MAX> 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<Symlinks_resolved_ok, Symlink_resolve_error>;
Symlink_resolve_result resolve_symlinks(char const *path,
Absolute_path &resolved_path);
} }
#endif /* _LIBC__INTERNAL__FILE_OPERATIONS_H_ */ #endif /* _LIBC__INTERNAL__FILE_OPERATIONS_H_ */

View File

@ -35,10 +35,6 @@ namespace Libc {
typedef Genode::Path<PATH_MAX> Absolute_path; typedef Genode::Path<PATH_MAX> Absolute_path;
class Symlink_resolve_error : Genode::Exception { };
void resolve_symlinks(char const *path, Absolute_path &resolved_path);
class Plugin : public List<Plugin>::Element class Plugin : public List<Plugin>::Element
{ {
protected: protected:

View File

@ -15,6 +15,7 @@
/* libc-internal includes */ /* libc-internal includes */
#include <internal/kernel.h> #include <internal/kernel.h>
#include <internal/file_operations.h>
Libc::Kernel * Libc::Kernel::_kernel_ptr; Libc::Kernel * Libc::Kernel::_kernel_ptr;
@ -84,7 +85,8 @@ void Libc::Kernel::_init_file_descriptors()
} diag_guard { *this }; } 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 path_element[PATH_MAX];
char symlink_target[PATH_MAX]; char symlink_target[PATH_MAX];
@ -97,7 +99,7 @@ void Libc::Kernel::_init_file_descriptors()
do { do {
if (follow_count++ == FOLLOW_LIMIT) { if (follow_count++ == FOLLOW_LIMIT) {
errno = ELOOP; errno = ELOOP;
throw Symlink_resolve_error(); return Symlink_resolve_error();
} }
current_iteration_working_path = next_iteration_working_path; 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); next_iteration_working_path.append_element(path_element);
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
throw Symlink_resolve_error(); return Symlink_resolve_error();
} }
/* /*
@ -130,13 +132,13 @@ void Libc::Kernel::_init_file_descriptors()
struct stat stat_buf; struct stat stat_buf;
int res = _vfs.stat_from_kernel(next_iteration_working_path.base(), &stat_buf); int res = _vfs.stat_from_kernel(next_iteration_working_path.base(), &stat_buf);
if (res == -1) { if (res == -1) {
throw Symlink_resolve_error(); return Symlink_resolve_error();
} }
if (S_ISLNK(stat_buf.st_mode)) { if (S_ISLNK(stat_buf.st_mode)) {
res = readlink(next_iteration_working_path.base(), res = readlink(next_iteration_working_path.base(),
symlink_target, sizeof(symlink_target) - 1); symlink_target, sizeof(symlink_target) - 1);
if (res < 1) if (res < 1)
throw Symlink_resolve_error(); return Symlink_resolve_error();
/* zero terminate target */ /* zero terminate target */
symlink_target[res] = 0; symlink_target[res] = 0;
@ -151,7 +153,7 @@ void Libc::Kernel::_init_file_descriptors()
next_iteration_working_path.append_element(symlink_target); next_iteration_working_path.append_element(symlink_target);
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
throw Symlink_resolve_error(); return Symlink_resolve_error();
} }
} }
symlink_resolved_in_this_iteration = true; symlink_resolved_in_this_iteration = true;
@ -165,21 +167,28 @@ void Libc::Kernel::_init_file_descriptors()
resolved_path = next_iteration_working_path; resolved_path = next_iteration_working_path;
resolved_path.remove_trailing('/'); resolved_path.remove_trailing('/');
return Symlinks_resolved_ok();
}; };
typedef String<Vfs::MAX_PATH_LEN> Path; typedef String<Vfs::MAX_PATH_LEN> Path;
auto resolve_absolute_path = [&] (Path const &path) struct Absolute_path_resolved_ok { };
struct Absolute_path_resolve_error { };
using Absolute_path_resolve_result = Attempt<Absolute_path_resolved_ok,
Absolute_path_resolve_error>;
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 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(); Absolute_path dir_entry(path.string(), _cwd.base()); dir_entry.keep_only_last_element();
try { 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()); abs_path.append_element(dir_entry.string());
return abs_path; return Absolute_path_resolved_ok();
} catch (Path_base::Path_too_long) { return Absolute_path(); } } catch (Path_base::Path_too_long) { return Absolute_path_resolve_error(); }
}; };
auto init_fd = [&] (Xml_node const &node, char const *attr, auto init_fd = [&] (Xml_node const &node, char const *attr,
@ -189,8 +198,14 @@ void Libc::Kernel::_init_file_descriptors()
return; return;
Path const attr_value { node.attribute_value(attr, Path()) }; Path const attr_value { node.attribute_value(attr, Path()) };
try {
Absolute_path const path { resolve_absolute_path(attr_value) }; Absolute_path path { };
if (resolve_absolute_path(attr_value, path).failed()) {
warning("failed to resolve path for ", path);
diag_guard.show = true;
return;
}
struct stat out_stat { }; struct stat out_stat { };
if (_vfs.stat_from_kernel(path.string(), &out_stat) != 0) { if (_vfs.stat_from_kernel(path.string(), &out_stat) != 0) {
@ -232,12 +247,6 @@ void Libc::Kernel::_init_file_descriptors()
::off_t const seek = node.attribute_value("seek", 0ULL); ::off_t const seek = node.attribute_value("seek", 0ULL);
if (seek) if (seek)
_vfs.lseek_from_kernel(fd, seek); _vfs.lseek_from_kernel(fd, seek);
} catch (Symlink_resolve_error) {
warning("failed to resolve path for ", attr_value);
diag_guard.show = true;
return;
}
}; };
if (_vfs.root_dir_has_dirents()) { if (_vfs.root_dir_has_dirents()) {