mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
Check for symlink target length errors
Check for symlink length errors at the VFS library and the ram_fs and vfs servers. Fix #2462
This commit is contained in:
parent
cfdac3f4c3
commit
2deddf1e6d
@ -706,7 +706,7 @@ int Libc::Vfs_plugin::symlink(const char *oldpath, const char *newpath)
|
||||
case Result::SYMLINK_ERR_EXISTS: errno = EEXIST; return -1;
|
||||
case Result::SYMLINK_ERR_NO_ENTRY: errno = ENOENT; return -1;
|
||||
case Result::SYMLINK_ERR_NAME_TOO_LONG: errno = ENAMETOOLONG; return -1;
|
||||
case Result::SYMLINK_ERR_NO_PERM: errno = ENOSYS; return -1;
|
||||
case Result::SYMLINK_ERR_NO_PERM: errno = EPERM; return -1;
|
||||
case Result::SYMLINK_ERR_NO_SPACE: errno = ENOSPC; return -1;
|
||||
case Result::SYMLINK_OK: break;
|
||||
}
|
||||
|
@ -530,6 +530,8 @@ class Vfs::Fs_file_system : public File_system
|
||||
|
||||
Symlink_result symlink(char const *from, char const *to) override
|
||||
{
|
||||
auto const from_len = strlen(from);
|
||||
|
||||
/*
|
||||
* We write to the symlink via the packet stream. Hence we need
|
||||
* to serialize with other packet-stream operations.
|
||||
@ -550,10 +552,18 @@ class Vfs::Fs_file_system : public File_system
|
||||
Fs_handle_guard from_dir_guard(*this, _fs, dir_handle, _handle_space);
|
||||
|
||||
::File_system::Symlink_handle symlink_handle =
|
||||
_fs.symlink(dir_handle, symlink_name.base() + 1, true);
|
||||
_fs.symlink(dir_handle, symlink_name.base() + 1, true);
|
||||
Fs_handle_guard symlink_guard(*this, _fs, symlink_handle, _handle_space);
|
||||
|
||||
_write(symlink_guard, from, strlen(from) + 1, 0);
|
||||
auto const n = _write(symlink_guard, from, from_len, 0);
|
||||
|
||||
/*
|
||||
* a convention at the VFS server is to return an invalid
|
||||
* result length when the target is too long
|
||||
*/
|
||||
if (n != from_len) {
|
||||
return n ? SYMLINK_ERR_NAME_TOO_LONG : SYMLINK_ERR_NO_PERM;
|
||||
}
|
||||
}
|
||||
catch (::File_system::Invalid_handle) { return SYMLINK_ERR_NO_ENTRY; }
|
||||
catch (::File_system::Node_already_exists) { return SYMLINK_ERR_EXISTS; }
|
||||
|
@ -246,7 +246,7 @@ class Vfs_ram::Symlink : public Vfs_ram::Node
|
||||
|
||||
void set(char const *target, size_t len)
|
||||
{
|
||||
_len = min(len, MAX_PATH_LEN);
|
||||
_len = len;
|
||||
memcpy(_target, target, _len);
|
||||
}
|
||||
|
||||
@ -579,6 +579,10 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
{
|
||||
using namespace Vfs_ram;
|
||||
|
||||
auto const target_len = strlen(target);
|
||||
if (target_len > MAX_PATH_LEN)
|
||||
return SYMLINK_ERR_NAME_TOO_LONG;
|
||||
|
||||
Symlink *link;
|
||||
Directory *parent = lookup_parent(path);
|
||||
if (!parent) return SYMLINK_ERR_NO_ENTRY;
|
||||
@ -606,7 +610,7 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
}
|
||||
|
||||
if (*target)
|
||||
link->set(target, strlen(target));
|
||||
link->set(target, target_len);
|
||||
link->unlock();
|
||||
return SYMLINK_OK;
|
||||
}
|
||||
|
@ -43,8 +43,6 @@ class Ram_fs::Symlink : public Node
|
||||
/* Ideal symlink operations are atomic. */
|
||||
if (seek_offset) return 0;
|
||||
|
||||
len = min(len, sizeof(_link_to));
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (src[i] == '\0') {
|
||||
len = i;
|
||||
@ -52,6 +50,13 @@ class Ram_fs::Symlink : public Node
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if the target is too long return a
|
||||
* short result to indicate the error
|
||||
*/
|
||||
if (len > sizeof(_link_to))
|
||||
return len >> 1;
|
||||
|
||||
Genode::memcpy(_link_to, src, len);
|
||||
_len = len;
|
||||
return len;
|
||||
|
@ -132,15 +132,30 @@ struct Vfs_server::Symlink : Node
|
||||
|
||||
size_t write(Vfs::File_system &vfs, char const *src, size_t len, seek_off_t seek_offset)
|
||||
{
|
||||
/* ensure symlink gets something null-terminated */
|
||||
Genode::String<MAX_PATH_LEN> target(Genode::Cstring(src, len));
|
||||
/*
|
||||
* if the symlink target is too long return a short result
|
||||
* because a competent File_system client will error on a
|
||||
* length mismatch
|
||||
*/
|
||||
|
||||
if (vfs.symlink(target.string(), path()) == Directory_service::SYMLINK_OK)
|
||||
return 0;
|
||||
if (len > MAX_PATH_LEN) {
|
||||
return len >> 1;
|
||||
}
|
||||
|
||||
/* ensure symlink gets something null-terminated */
|
||||
Genode::String<MAX_PATH_LEN+1> target(Genode::Cstring(src, len));
|
||||
size_t const target_len = target.length()-1;
|
||||
|
||||
switch (vfs.symlink(target.string(), path())) {
|
||||
case Directory_service::SYMLINK_OK: break;
|
||||
case Directory_service::SYMLINK_ERR_NAME_TOO_LONG:
|
||||
return target_len >> 1;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
mark_as_updated();
|
||||
notify_listeners();
|
||||
return target.length();
|
||||
return target_len;
|
||||
}
|
||||
|
||||
bool read_ready() override { return true; }
|
||||
|
Loading…
Reference in New Issue
Block a user