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++) {
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);
}

View File

@ -41,6 +41,7 @@ extern "C" {
#include <internal/plugin_registry.h>
#include <internal/plugin.h>
#include <internal/file.h>
#include <internal/file_operations.h>
#include <internal/mem_alloc.h>
#include <internal/mmap_registry.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
*/
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());
}

View File

@ -28,7 +28,12 @@ namespace Libc {
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_ */

View File

@ -35,10 +35,6 @@ namespace Libc {
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
{
protected:

View File

@ -15,6 +15,7 @@
/* libc-internal includes */
#include <internal/kernel.h>
#include <internal/file_operations.h>
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<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 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()) {