Kernel: Fix pseudo terminal leaks

This commit is contained in:
Bananymous 2024-11-04 15:35:07 +02:00
parent a356d90445
commit 1838ea5c30
3 changed files with 45 additions and 9 deletions

View File

@ -62,10 +62,12 @@ namespace Kernel
void putchar_impl(uint8_t ch) override; void putchar_impl(uint8_t ch) override;
private: private:
PseudoTerminalSlave(BAN::String&& name, mode_t, uid_t, gid_t); PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t, uid_t, gid_t);
~PseudoTerminalSlave();
private: private:
BAN::String m_name; const BAN::String m_name;
const uint32_t m_number;
BAN::WeakPtr<PseudoTerminalMaster> m_master; BAN::WeakPtr<PseudoTerminalMaster> m_master;
uint32_t m_width { 0 }; uint32_t m_width { 0 };

View File

@ -1790,13 +1790,13 @@ namespace Kernel
LockGuard _(m_process_lock); LockGuard _(m_process_lock);
TRY(validate_pointer_access(buffer, buffer_len, true)); TRY(validate_pointer_access(buffer, buffer_len, true));
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
if (TRY(m_open_file_descriptors.path_of(fildes)) != "<ptmx>"_sv) if (TRY(m_open_file_descriptors.path_of(fildes)) != "<ptmx>"_sv)
return BAN::Error::from_errno(ENOTTY); return BAN::Error::from_errno(ENOTTY);
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
auto ptsname = TRY(static_cast<PseudoTerminalMaster*>(inode.ptr())->ptsname()); auto ptsname = TRY(static_cast<PseudoTerminalMaster*>(inode.ptr())->ptsname());
const size_t to_copy = BAN::Math::min(ptsname.size() + 1, buffer_len); const size_t to_copy = BAN::Math::min(ptsname.size(), buffer_len - 1);
memcpy(buffer, ptsname.data(), to_copy); memcpy(buffer, ptsname.data(), to_copy);
buffer[to_copy] = '\0'; buffer[to_copy] = '\0';

View File

@ -2,16 +2,41 @@
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Terminal/PseudoTerminal.h> #include <kernel/Terminal/PseudoTerminal.h>
#include <BAN/ScopeGuard.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
namespace Kernel namespace Kernel
{ {
BAN::Atomic<uint32_t> s_pts_master_minor = 0; static BAN::Atomic<uint32_t> s_pts_master_minor = 0;
BAN::Atomic<uint32_t> s_pts_slave_number = 0;
static SpinLock s_pts_slave_bitmap_lock;
static uint64_t s_pts_slave_bitmap = 0;
BAN::ErrorOr<BAN::RefPtr<PseudoTerminalMaster>> PseudoTerminalMaster::create(mode_t mode, uid_t uid, gid_t gid) BAN::ErrorOr<BAN::RefPtr<PseudoTerminalMaster>> PseudoTerminalMaster::create(mode_t mode, uid_t uid, gid_t gid)
{ {
size_t pts_slave_number = 0;
{
SpinLockGuard _(s_pts_slave_bitmap_lock);
for (pts_slave_number = 0; pts_slave_number < sizeof(s_pts_slave_bitmap) * 8; pts_slave_number++)
{
if (s_pts_slave_bitmap & ((uint64_t)1 << pts_slave_number))
continue;
s_pts_slave_bitmap |= (uint64_t)1 << pts_slave_number;
break;
}
}
if (pts_slave_number >= sizeof(s_pts_slave_bitmap) * 8)
return BAN::Error::from_errno(ENODEV);
BAN::ScopeGuard slave_number_clearer(
[pts_slave_number]()
{
SpinLockGuard _(s_pts_slave_bitmap_lock);
s_pts_slave_bitmap &= ~((uint64_t)1 << pts_slave_number);
}
);
auto pts_master_buffer = TRY(VirtualRange::create_to_vaddr_range( auto pts_master_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(), PageTable::kernel(),
KERNEL_OFFSET, static_cast<vaddr_t>(-1), KERNEL_OFFSET, static_cast<vaddr_t>(-1),
@ -19,9 +44,11 @@ namespace Kernel
PageTable::Flags::ReadWrite | PageTable::Flags::Present, true PageTable::Flags::ReadWrite | PageTable::Flags::Present, true
)); ));
auto pts_master = TRY(BAN::RefPtr<PseudoTerminalMaster>::create(BAN::move(pts_master_buffer), mode, uid, gid)); auto pts_master = TRY(BAN::RefPtr<PseudoTerminalMaster>::create(BAN::move(pts_master_buffer), mode, uid, gid));
DevFileSystem::get().remove_from_cache(pts_master);
auto pts_slave_name = TRY(BAN::String::formatted("pts{}", s_pts_slave_number++)); auto pts_slave_name = TRY(BAN::String::formatted("pts{}", pts_slave_number));
auto pts_slave = TRY(BAN::RefPtr<PseudoTerminalSlave>::create(BAN::move(pts_slave_name), 0610, uid, gid)); auto pts_slave = TRY(BAN::RefPtr<PseudoTerminalSlave>::create(BAN::move(pts_slave_name), pts_slave_number, 0610, uid, gid));
slave_number_clearer.disable();
pts_master->m_slave = TRY(pts_slave->get_weak_ptr()); pts_master->m_slave = TRY(pts_slave->get_weak_ptr());
pts_slave->m_master = TRY(pts_master->get_weak_ptr()); pts_slave->m_master = TRY(pts_master->get_weak_ptr());
@ -112,11 +139,18 @@ namespace Kernel
return buffer.size(); return buffer.size();
} }
PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, mode_t mode, uid_t uid, gid_t gid) PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t mode, uid_t uid, gid_t gid)
: TTY(mode, uid, gid) : TTY(mode, uid, gid)
, m_name(BAN::move(name)) , m_name(BAN::move(name))
, m_number(number)
{} {}
PseudoTerminalSlave::~PseudoTerminalSlave()
{
SpinLockGuard _(s_pts_slave_bitmap_lock);
s_pts_slave_bitmap &= ~((uint64_t)1 << m_number);
}
void PseudoTerminalSlave::clear() void PseudoTerminalSlave::clear()
{ {
const char message[] { '\e', '[', '2', 'J' }; const char message[] { '\e', '[', '2', 'J' };