From e6954d2e49a4b5c38126ccefd8e0eaf45636934d Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 16 Apr 2023 11:25:32 +0200 Subject: [PATCH] kernel: Disallow problematic characters, control characters and invalid UTF-8 in filenames --- kernel/src/fs/VFS.cpp | 35 +++++++++++++++++++++++++++++++++++ kernel/src/fs/VFS.h | 3 +++ kernel/src/sys/mknod.cpp | 2 ++ 3 files changed, 40 insertions(+) diff --git a/kernel/src/fs/VFS.cpp b/kernel/src/fs/VFS.cpp index 90f24971..4ff45dd3 100644 --- a/kernel/src/fs/VFS.cpp +++ b/kernel/src/fs/VFS.cpp @@ -3,6 +3,7 @@ #include "thread/Thread.h" #include #include +#include namespace VFS { @@ -46,6 +47,8 @@ namespace VFS auto child_name = TRY(parser.basename()); + TRY(validate_filename(child_name.view())); + return parent_inode->create_subdirectory(child_name.chars()); } @@ -60,9 +63,41 @@ namespace VFS auto child_name = TRY(parser.basename()); + TRY(validate_filename(child_name.view())); + return parent_inode->create_file(child_name.chars()); } + Result validate_filename(StringView name) + { + // Forbid problematic characters that could cause trouble in shell scripts and the like. + if (strpbrk(name.chars(), "*?:[]\"<>\\")) return err(EINVAL); + + // Forbid filenames starting with a hyphen. + if (!name.is_empty() && name[0] == '-') return err(EINVAL); + + // Forbid filenames with leading spaces. + if (!name.is_empty() && name[0] == ' ') return err(EINVAL); + + // Forbid filenames with trailing spaces. + if (!name.is_empty() && name[name.length() - 1] == ' ') return err(EINVAL); + + for (const auto& c : name) + { + // Forbid filenames with control characters. + if (c < 32 || c == 127) return err(EINVAL); + } + + // Forbid filenames that are not valid UTF-8. + + Utf8StringDecoder decoder(name.chars()); + + // This will fail if the filename is invalid UTF-8. + TRY(decoder.code_points()); + + return {}; + } + bool can_execute(SharedPtr inode, Credentials auth) { if (inode->uid() == auth.euid) { return inode->mode() & S_IXUSR; } diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index d86395a2..9e550a99 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include struct Credentials; @@ -211,6 +212,8 @@ namespace VFS Result> create_file(const char* path, Credentials auth, SharedPtr working_directory = {}); + Result validate_filename(StringView name); + bool can_execute(SharedPtr inode, Credentials auth); bool can_read(SharedPtr inode, Credentials auth); bool can_write(SharedPtr inode, Credentials auth); diff --git a/kernel/src/sys/mknod.cpp b/kernel/src/sys/mknod.cpp index 9cdf8d64..3240efdf 100644 --- a/kernel/src/sys/mknod.cpp +++ b/kernel/src/sys/mknod.cpp @@ -22,6 +22,8 @@ Result sys_mknod(Registers*, SyscallArgs args) auto dirname = TRY(parser.dirname()); auto basename = TRY(parser.basename()); + TRY(VFS::validate_filename(basename.view())); + auto parent = TRY(VFS::resolve_path(dirname.chars(), current->auth, current->current_directory)); if (!VFS::can_write(parent, current->auth)) return err(EACCES);