Compare commits

...

8 Commits

Author SHA1 Message Date
Bananymous 1d470fb5ba Kernel: All syscalls now validate users pointers
We now validate pointers passed by the user, to forbid arbitary
memory read/write. Now the user is only allowed to pass in pointers
in their own mapped memory space (or null).
2023-09-25 22:07:12 +03:00
Bananymous b4e4f7a6cc Kernel: Print more detailed output on ISR 2023-09-25 20:33:07 +03:00
Bananymous 55d30a7cc3 Kernel: Ext2 inodes are now stored in cache
This allows faster inode access and ensures working inodes when
opened in multiple places.
2023-09-25 20:31:40 +03:00
Bananymous b62186441b BAN: Implement basic WeakPtr
This can be constructed from classes that inherit from Weakable
2023-09-25 19:43:10 +03:00
Bananymous 8caba1e774 Kernel: Ext2 filesystem now holds 10 preallocated block buffers
Inodes can query blocks from this buffer. This allows allocation of
blocks to not fail during normal operations. Also less stress on
kmalloc.
2023-09-25 14:32:25 +03:00
Bananymous 7bdb428938 Kernel: Fix ext2 block allocation
Redo ext2 block allocation. This is now much "cleaner" although
I'm not too fond of the macros.
2023-09-25 13:17:44 +03:00
Bananymous 3ea707c0e7 BuildSystem: Optimize image creation
We now use truncate to create disk image, since it doesn't require
writing zeroes to full disk. I also removed creation of third
partition as this was not currently used.
2023-09-25 13:15:55 +03:00
Bananymous 18d582c6ce Kernel: Hacky kmalloc quick fix
Remove GeneralAllocator from kmalloc as it is not CriticalScope safe.
This requires increasing kmalloc memory.
2023-09-25 13:13:57 +03:00
13 changed files with 571 additions and 281 deletions

107
BAN/include/BAN/WeakPtr.h Normal file
View File

@ -0,0 +1,107 @@
#pragma once
#include <BAN/RefPtr.h>
namespace BAN
{
template<typename T>
class Weakable;
template<typename T>
class WeakPtr;
template<typename T>
class WeakLink : public RefCounted<WeakLink<T>>
{
public:
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
T* raw_ptr() { return m_ptr; }
bool valid() const { return m_ptr; }
void invalidate() { m_ptr = nullptr; }
private:
WeakLink(T* ptr) : m_ptr(ptr) {}
private:
T* m_ptr;
friend class RefPtr<WeakLink<T>>;
};
template<typename T>
class Weakable
{
public:
~Weakable()
{
if (m_link)
m_link->invalidate();
}
ErrorOr<WeakPtr<T>> get_weak_ptr() const
{
if (!m_link)
m_link = TRY(RefPtr<WeakLink<T>>::create((T*)this));
return WeakPtr<T>(m_link);
}
private:
mutable RefPtr<WeakLink<T>> m_link;
};
template<typename T>
class WeakPtr
{
public:
WeakPtr() = default;
WeakPtr(WeakPtr&& other) { *this = move(other); }
WeakPtr(const WeakPtr& other) { *this = other; }
WeakPtr(const RefPtr<T>& other) { *this = other; }
WeakPtr& operator=(WeakPtr&& other)
{
clear();
m_link = move(other.m_link);
return *this;
}
WeakPtr& operator=(const WeakPtr& other)
{
clear();
m_link = other.m_link;
return *this;
}
WeakPtr& operator=(const RefPtr<T>& other)
{
clear();
if (other)
m_link = MUST(other->get_weak_ptr()).move_link();
return *this;
}
RefPtr<T> lock()
{
if (m_link->valid())
return m_link->lock();
return nullptr;
}
void clear() { m_link.clear(); }
bool valid() const { return m_link && m_link->valid(); }
private:
WeakPtr(const RefPtr<WeakLink<T>>& link)
: m_link(link)
{ }
RefPtr<WeakLink<T>>&& move_link() { return move(m_link); }
private:
RefPtr<WeakLink<T>> m_link;
friend class Weakable<T>;
};
}

View File

@ -4,7 +4,8 @@ set -e
DISK_SIZE=$[50 * 1024 * 1024]
MOUNT_DIR=/mnt
dd if=/dev/zero of=$DISK_IMAGE_PATH bs=512 count=$[$DISK_SIZE / 512] > /dev/null
truncate -s 0 $DISK_IMAGE_PATH
truncate -s $DISK_SIZE $DISK_IMAGE_PATH
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/null
g # gpt
@ -12,10 +13,6 @@ sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/n
1 # partition number 1
# default (from the beginning of the disk)
+1MiB # bios boot partiton size
n # new partition
3 # partition number 3
# default (right after bios boot partition)
+10Mib# partition size
n # new partition
2 # partition number 2
# default (right after bios boot partition)
@ -26,9 +23,6 @@ sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/n
t # set type
2 # ... of partition 2
20 # Linux filesystem
t # set type
3 # ... of partition 3
20 # Linux filesystem
w # write changes
EOF
@ -37,13 +31,11 @@ sudo partprobe $LOOP_DEV
PARTITION1=${LOOP_DEV}p1
PARTITION2=${LOOP_DEV}p2
PARTITION3=${LOOP_DEV}p3
sudo mkfs.ext2 $PARTITION3 > /dev/null
sudo mkfs.ext2 -d $SYSROOT $PARTITION2 > /dev/null
sudo mkfs.ext2 -d $SYSROOT -b 1024 -q $PARTITION2
sudo mount $PARTITION2 $MOUNT_DIR
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV > /dev/null
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV
sudo umount $MOUNT_DIR
sudo losetup -d $LOOP_DEV

View File

@ -148,6 +148,31 @@ namespace IDT
pid_t tid = Kernel::Scheduler::current_tid();
pid_t pid = tid ? Kernel::Process::current().pid() : 0;
if (tid)
{
auto start = Kernel::Thread::current().stack_base();
auto end = start + Kernel::Thread::current().stack_size();
if (interrupt_stack.rsp < start)
derrorln("Stack overflow");
if (interrupt_stack.rsp >= end)
derrorln("Stack underflow");
}
if (Kernel::PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & Kernel::PageTable::Flags::Present)
{
uint8_t* machine_code = (uint8_t*)interrupt_stack.rip;
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
machine_code[0],
machine_code[1],
machine_code[2],
machine_code[3],
machine_code[4],
machine_code[5],
machine_code[6],
machine_code[7]
);
}
dwarnln(
"{} (error code: 0x{16H}), pid {}, tid {}\r\n"
"Register dump\r\n"
@ -161,6 +186,8 @@ namespace IDT
regs->rip, regs->rflags,
regs->cr0, regs->cr2, regs->cr3, regs->cr4
);
if (isr == ISR::PageFault)
Kernel::PageTable::current().debug_dump();
Debug::dump_stack_trace();
if (tid)

View File

@ -1,5 +1,6 @@
#pragma once
#include <BAN/HashMap.h>
#include <kernel/Storage/StorageDevice.h>
#include <kernel/FS/FileSystem.h>
#include <kernel/FS/Ext2/Inode.h>
@ -9,6 +10,37 @@ namespace Kernel
class Ext2FS final : public FileSystem
{
public:
class BlockBufferWrapper
{
BAN_NON_COPYABLE(BlockBufferWrapper);
BAN_NON_MOVABLE(BlockBufferWrapper);
public:
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool& used)
: m_buffer(buffer)
, m_used(used)
{
ASSERT(m_used);
}
~BlockBufferWrapper()
{
m_used = false;
}
size_t size() const { return m_buffer.size(); }
uint8_t* data() { return m_buffer.data(); }
const uint8_t* data() const { return m_buffer.data(); }
uint8_t& operator[](size_t index) { return m_buffer[index]; }
uint8_t operator[](size_t index) const { return m_buffer[index]; }
private:
BAN::Span<uint8_t> m_buffer;
bool& m_used;
};
public:
static BAN::ErrorOr<Ext2FS*> create(Partition&);
@ -26,12 +58,16 @@ namespace Kernel
BAN::ErrorOr<void> delete_inode(uint32_t);
BAN::ErrorOr<void> resize_inode(uint32_t, size_t);
void read_block(uint32_t, BAN::Span<uint8_t>);
void write_block(uint32_t, BAN::Span<const uint8_t>);
void read_block(uint32_t, BlockBufferWrapper&);
void write_block(uint32_t, const BlockBufferWrapper&);
void sync_superblock();
BlockBufferWrapper get_block_buffer();
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
BAN::HashMap<ino_t, BAN::RefPtr<Inode>>& inode_cache() { return m_inode_cache; }
const Ext2::Superblock& superblock() const { return m_superblock; }
struct BlockLocation
@ -39,11 +75,30 @@ namespace Kernel
uint32_t block;
uint32_t offset;
};
BAN::ErrorOr<BlockLocation> locate_inode(uint32_t);
BlockLocation locate_inode(uint32_t);
BlockLocation locate_block_group_descriptior(uint32_t);
uint32_t block_size() const { return 1024 << superblock().log_block_size; }
class BlockBufferManager
{
public:
BlockBufferManager() = default;
BlockBufferWrapper get_buffer();
BAN::ErrorOr<void> initialize(size_t block_size);
private:
struct BlockBuffer
{
BAN::Vector<uint8_t> buffer;
bool used { false };
};
private:
BAN::Array<BlockBuffer, 10> m_buffers;
};
private:
RecursiveSpinLock m_lock;
@ -52,6 +107,10 @@ namespace Kernel
BAN::RefPtr<Inode> m_root_inode;
BAN::Vector<uint32_t> m_superblock_backups;
BAN::HashMap<ino_t, BAN::RefPtr<Inode>> m_inode_cache;
BlockBufferManager m_buffer_manager;
Ext2::Superblock m_superblock;
friend class Ext2Inode;

View File

@ -39,9 +39,8 @@ namespace Kernel
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
private:
BAN::ErrorOr<void> for_data_block_index(uint32_t, const BAN::Function<void(uint32_t&)>&, bool allocate);
uint32_t fs_block_of_data_block_index(uint32_t data_block_index);
BAN::ErrorOr<uint32_t> data_block_index(uint32_t);
BAN::ErrorOr<uint32_t> allocate_new_block();
BAN::ErrorOr<void> sync();

View File

@ -87,8 +87,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_getpgid(pid_t);
BAN::ErrorOr<void> create_file(BAN::StringView name, mode_t mode);
BAN::ErrorOr<long> sys_open(BAN::StringView, int, mode_t = 0);
BAN::ErrorOr<long> sys_openat(int, BAN::StringView, int, mode_t = 0);
BAN::ErrorOr<long> open_file(BAN::StringView path, int, mode_t = 0);
BAN::ErrorOr<long> sys_open(const char* path, int, mode_t);
BAN::ErrorOr<long> sys_openat(int, const char* path, int, mode_t);
BAN::ErrorOr<long> sys_close(int fd);
BAN::ErrorOr<long> sys_read(int fd, void* buffer, size_t count);
BAN::ErrorOr<long> sys_write(int fd, const void* buffer, size_t count);
@ -112,7 +113,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_read_dir_entries(int fd, DirectoryEntryList* buffer, size_t buffer_size);
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t&);
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
BAN::ErrorOr<long> sys_signal(int, void (*)(int));
@ -121,9 +122,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);
BAN::ErrorOr<long> sys_termid(char*) const;
BAN::ErrorOr<long> sys_termid(char*);
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*) const;
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
TTY& tty() { ASSERT(m_controlling_terminal); return *m_controlling_terminal; }
@ -149,6 +150,9 @@ namespace Kernel
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;
void validate_string_access(const char*);
void validate_pointer_access(const void*, size_t);
private:
struct ExitStatus
{

View File

@ -90,16 +90,17 @@ namespace Kernel
dprintln(" inodes/group {}", m_superblock.inodes_per_group);
#endif
TRY(m_buffer_manager.initialize(block_size()));
{
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size()));
auto block_buffer = m_buffer_manager.get_buffer();
if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV)
{
// In revision 0 all blockgroups contain superblock backup
TRY(m_superblock_backups.reserve(number_of_block_groups - 1));
for (uint32_t i = 1; i < number_of_block_groups; i++)
MUST(block_buffer.push_back(i));
MUST(m_superblock_backups.push_back(i));
}
else
{
@ -118,7 +119,7 @@ namespace Kernel
for (uint32_t bg : m_superblock_backups)
{
read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer.span());
read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer);
Ext2::Superblock& superblock_backup = *(Ext2::Superblock*)block_buffer.data();
if (superblock_backup.magic != Ext2::Enum::SUPER_MAGIC)
derrorln("superblock backup at block {} is invalid ({4H})", bg, superblock_backup.magic);
@ -145,11 +146,8 @@ namespace Kernel
const uint32_t block_size = this->block_size();
BAN::Vector<uint8_t> bgd_buffer;
TRY(bgd_buffer.resize(block_size));
BAN::Vector<uint8_t> inode_bitmap;
TRY(inode_bitmap.resize(block_size));
auto bgd_buffer = m_buffer_manager.get_buffer();
auto inode_bitmap = m_buffer_manager.get_buffer();
uint32_t current_group = -1;
BlockLocation bgd_location {};
@ -165,7 +163,7 @@ namespace Kernel
current_group = ino_group;
bgd_location = locate_block_group_descriptior(current_group);
read_block(bgd_location.block, bgd_buffer.span());
read_block(bgd_location.block, bgd_buffer);
bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd->free_inodes_count == 0)
@ -174,7 +172,7 @@ namespace Kernel
continue;
}
read_block(bgd->inode_bitmap, inode_bitmap.span());
read_block(bgd->inode_bitmap, inode_bitmap);
}
const uint32_t ino_bitmap_byte = ino_index / 8;
@ -183,10 +181,10 @@ namespace Kernel
continue;
inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit;
write_block(bgd->inode_bitmap, inode_bitmap.span());
write_block(bgd->inode_bitmap, inode_bitmap);
bgd->free_inodes_count--;
write_block(bgd_location.block, bgd_buffer.span());
write_block(bgd_location.block, bgd_buffer);
const uint32_t inode_table_offset = ino_index * superblock().inode_size;
const BlockLocation inode_location
@ -198,11 +196,11 @@ namespace Kernel
// NOTE: we don't need inode bitmap anymore, so we can reuse it
auto& inode_buffer = inode_bitmap;
read_block(inode_location.block, inode_buffer.span());
read_block(inode_location.block, inode_buffer);
memcpy(inode_buffer.data() + inode_location.offset, &ext2_inode, sizeof(Ext2::Inode));
if (superblock().inode_size > sizeof(Ext2::Inode))
memset(inode_buffer.data() + inode_location.offset + sizeof(Ext2::Inode), 0, superblock().inode_size - sizeof(Ext2::Inode));
write_block(inode_location.block, inode_buffer.span());
write_block(inode_location.block, inode_buffer);
m_superblock.free_inodes_count--;
sync_superblock();
@ -214,7 +212,7 @@ namespace Kernel
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
}
void Ext2FS::read_block(uint32_t block, BAN::Span<uint8_t> buffer)
void Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
{
LockGuard _(m_lock);
@ -228,7 +226,7 @@ namespace Kernel
MUST(m_partition.read_sectors(sectors_before + (block - 2) * sectors_per_block, sectors_per_block, buffer.data()));
}
void Ext2FS::write_block(uint32_t block, BAN::Span<const uint8_t> buffer)
void Ext2FS::write_block(uint32_t block, const BlockBufferWrapper& buffer)
{
LockGuard _(m_lock);
@ -268,6 +266,13 @@ namespace Kernel
}
}
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
{
LockGuard _(m_lock);
return m_buffer_manager.get_buffer();
}
BAN::ErrorOr<uint32_t> Ext2FS::reserve_free_block(uint32_t primary_bgd)
{
LockGuard _(m_lock);
@ -275,25 +280,20 @@ namespace Kernel
if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count)
return BAN::Error::from_errno(ENOSPC);
const uint32_t block_size = this->block_size();
BAN::Vector<uint8_t> bgd_buffer;
TRY(bgd_buffer.resize(block_size));
BAN::Vector<uint8_t> block_bitmap;
TRY(block_bitmap.resize(block_size));
auto bgd_buffer = m_buffer_manager.get_buffer();
auto block_bitmap = m_buffer_manager.get_buffer();
auto check_block_group =
[&](uint32_t block_group) -> uint32_t
{
auto bgd_location = locate_block_group_descriptior(block_group);
read_block(bgd_location.block, bgd_buffer.span());
read_block(bgd_location.block, bgd_buffer);
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd.free_blocks_count == 0)
return 0;
read_block(bgd.block_bitmap, block_bitmap.span());
read_block(bgd.block_bitmap, block_bitmap);
for (uint32_t block_offset = 0; block_offset < m_superblock.blocks_per_group; block_offset++)
{
const uint32_t fs_block_index = m_superblock.first_data_block + m_superblock.blocks_per_group * block_group + block_offset;
@ -306,10 +306,10 @@ namespace Kernel
continue;
block_bitmap[byte] |= 1 << bit;
write_block(bgd.block_bitmap, block_bitmap.span());
write_block(bgd.block_bitmap, block_bitmap);
bgd.free_blocks_count--;
write_block(bgd_location.block, bgd_buffer.span());
write_block(bgd_location.block, bgd_buffer);
m_superblock.free_blocks_count--;
sync_superblock();
@ -334,7 +334,7 @@ namespace Kernel
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
}
BAN::ErrorOr<Ext2FS::BlockLocation> Ext2FS::locate_inode(uint32_t ino)
Ext2FS::BlockLocation Ext2FS::locate_inode(uint32_t ino)
{
LockGuard _(m_lock);
@ -342,15 +342,14 @@ namespace Kernel
const uint32_t block_size = this->block_size();
BAN::Vector<uint8_t> bgd_buffer;
TRY(bgd_buffer.resize(block_size));
auto bgd_buffer = m_buffer_manager.get_buffer();
const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group;
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
auto bgd_location = locate_block_group_descriptior(inode_group);
read_block(bgd_location.block, bgd_buffer.span());
read_block(bgd_location.block, bgd_buffer);
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
@ -397,4 +396,26 @@ namespace Kernel
};
}
Ext2FS::BlockBufferWrapper Ext2FS::BlockBufferManager::get_buffer()
{
for (auto& buffer : m_buffers)
{
if (buffer.used)
continue;
buffer.used = true;
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), buffer.used);
}
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
{
for (auto& buffer : m_buffers)
{
TRY(buffer.buffer.resize(block_size));
buffer.used = false;
}
return {};
}
}

View File

@ -23,141 +23,74 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::create(Ext2FS& fs, uint32_t inode_ino)
{
auto inode_location = TRY(fs.locate_inode(inode_ino));
if (fs.inode_cache().contains(inode_ino))
return fs.inode_cache()[inode_ino];
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(fs.block_size()));
auto inode_location = fs.locate_inode(inode_ino);
fs.read_block(inode_location.block, block_buffer.span());
auto block_buffer = fs.get_block_buffer();
fs.read_block(inode_location.block, block_buffer);
auto& inode = *(Ext2::Inode*)(block_buffer.data() + inode_location.offset);
Ext2Inode* result = new Ext2Inode(fs, inode, inode_ino);
if (result == nullptr)
Ext2Inode* result_ptr = new Ext2Inode(fs, inode, inode_ino);
if (result_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<Inode>::adopt(result);
auto result = BAN::RefPtr<Inode>::adopt(result_ptr);
TRY(fs.inode_cache().insert(inode_ino, result));
return result;
}
#define READ_INDIRECT(block, container) \
if (block) \
m_fs.read_block(block, block_buffer.span()); \
else \
{ \
if (!allocate) \
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); \
memset(block_buffer.data(), 0, block_size); \
block = TRY(m_fs.reserve_free_block(block_group())); \
m_fs.write_block(container, block_buffer.span()); \
}
#define VERIFY_AND_READ_BLOCK(expr) do { const uint32_t block_index = expr; ASSERT(block_index); m_fs.read_block(block_index, block_buffer); } while (false)
#define VERIFY_AND_RETURN(expr) ({ const uint32_t result = expr; ASSERT(result); return result; })
#define READ_INDIRECT_TOP(block) \
if (block) \
m_fs.read_block(block, block_buffer.span()); \
else \
{ \
if (!allocate) \
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); \
memset(block_buffer.data(), 0, block_size); \
block = TRY(m_fs.reserve_free_block(block_group())); \
}
BAN::ErrorOr<void> Ext2Inode::for_data_block_index(uint32_t asked_data_block, const BAN::Function<void(uint32_t&)>& callback, bool allocate)
uint32_t Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index)
{
const uint32_t block_size = blksize();
const uint32_t data_blocks_count = blocks();
const uint32_t blocks_per_array = block_size / sizeof(uint32_t);
ASSERT(data_block_index < blocks());
ASSERT(asked_data_block < data_blocks_count);
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
// Direct block
if (asked_data_block < 12)
{
uint32_t& block = m_inode.block[asked_data_block];
uint32_t block_copy = block;
callback(block);
if (data_block_index < 12)
VERIFY_AND_RETURN(m_inode.block[data_block_index]);
if (block != block_copy)
TRY(sync());
data_block_index -= 12;
return {};
}
asked_data_block -= 12;
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
auto block_buffer = m_fs.get_block_buffer();
// Singly indirect block
if (asked_data_block < blocks_per_array)
if (data_block_index < indices_per_block)
{
READ_INDIRECT_TOP(m_inode.block[12]);
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block];
uint32_t block_copy = block;
callback(block);
if (block != block_copy)
m_fs.write_block(m_inode.block[12], block_buffer.span());
return {};
VERIFY_AND_READ_BLOCK(m_inode.block[12]);
VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index]);
}
asked_data_block -= blocks_per_array;
data_block_index -= indices_per_block;
// Doubly indirect blocks
if (asked_data_block < blocks_per_array * blocks_per_array)
if (data_block_index < indices_per_block * indices_per_block)
{
READ_INDIRECT_TOP(m_inode.block[13]);
uint32_t& direct_block = ((uint32_t*)block_buffer.data())[asked_data_block / blocks_per_array];
READ_INDIRECT(direct_block, m_inode.block[13]);
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block % blocks_per_array];
uint32_t block_copy = block;
callback(block);
if (block != block_copy)
m_fs.write_block(direct_block, block_buffer.span());
return {};
VERIFY_AND_READ_BLOCK(m_inode.block[13]);
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[data_block_index / indices_per_block]);
VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index % indices_per_block]);
}
asked_data_block -= blocks_per_array * blocks_per_array;
data_block_index -= indices_per_block * indices_per_block;
// Triply indirect blocks
if (asked_data_block < blocks_per_array * blocks_per_array * blocks_per_array)
if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
{
READ_INDIRECT_TOP(m_inode.block[14]);
uint32_t& doubly_indirect_block = ((uint32_t*)block_buffer.data())[asked_data_block / (blocks_per_array * blocks_per_array)];
READ_INDIRECT(doubly_indirect_block, m_inode.block[14]);
uint32_t& singly_direct_block = ((uint32_t*)block_buffer.data())[(asked_data_block / blocks_per_array) % blocks_per_array];
READ_INDIRECT(singly_direct_block, doubly_indirect_block);
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block % blocks_per_array];
uint32_t block_copy = block;
callback(block);
if (block != block_copy)
m_fs.write_block(singly_direct_block, block_buffer.span());
return {};
VERIFY_AND_READ_BLOCK(m_inode.block[14]);
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[data_block_index / (indices_per_block * indices_per_block)]);
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[(data_block_index / indices_per_block) % indices_per_block]);
VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index % indices_per_block]);
}
ASSERT_NOT_REACHED();
}
#undef READ_INDIRECT
#undef READ_INDIRECT_TOP
BAN::ErrorOr<uint32_t> Ext2Inode::data_block_index(uint32_t asked_data_block)
{
uint32_t result;
TRY(for_data_block_index(asked_data_block, [&result] (uint32_t& index) { result = index; }, false));
ASSERT(result != 0);
return result;
}
#undef VERIFY_AND_READ_BLOCK
#undef VERIFY_AND_RETURN
BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl()
{
@ -184,18 +117,17 @@ namespace Kernel
const uint32_t block_size = blksize();
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
auto block_buffer = m_fs.get_block_buffer();
const uint32_t first_block = offset / block_size;
const uint32_t last_block = BAN::Math::div_round_up<uint32_t>(offset + count, block_size);
size_t n_read = 0;
for (uint32_t block = first_block; block < last_block; block++)
for (uint32_t data_block_index = first_block; data_block_index < last_block; data_block_index++)
{
uint32_t block_index = TRY(data_block_index(block));
m_fs.read_block(block_index, block_buffer.span());
uint32_t block_index = fs_block_of_data_block_index(data_block_index);
m_fs.read_block(block_index, block_buffer);
uint32_t copy_offset = (offset + n_read) % block_size;
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - copy_offset, count - n_read);
@ -222,8 +154,7 @@ namespace Kernel
const uint32_t block_size = blksize();
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
auto block_buffer = m_fs.get_block_buffer();
const uint8_t* u8buffer = (const uint8_t*)buffer;
@ -232,15 +163,14 @@ namespace Kernel
// Write partial block
if (offset % block_size)
{
uint32_t block_index = offset / block_size;
uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
uint32_t block_offset = offset % block_size;
uint32_t data_block_index = TRY(this->data_block_index(block_index));
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write);
m_fs.read_block(data_block_index, block_buffer.span());
memcpy(block_buffer.data() + block_offset, buffer, to_copy);
m_fs.write_block(data_block_index, block_buffer.span());
m_fs.read_block(block_index, block_buffer);
memcpy(block_buffer.data() + block_offset, u8buffer, to_copy);
m_fs.write_block(block_index, block_buffer);
u8buffer += to_copy;
offset += to_copy;
@ -249,9 +179,10 @@ namespace Kernel
while (to_write >= block_size)
{
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size));
uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
m_fs.write_block(data_block_index, BAN::Span<const uint8_t>(u8buffer, block_size));
memcpy(block_buffer.data(), u8buffer, block_buffer.size());
m_fs.write_block(block_index, block_buffer);
u8buffer += block_size;
offset += block_size;
@ -260,11 +191,11 @@ namespace Kernel
if (to_write > 0)
{
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size));
uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
m_fs.read_block(data_block_index, block_buffer.span());
m_fs.read_block(block_index, block_buffer);
memcpy(block_buffer.data(), u8buffer, to_write);
m_fs.write_block(data_block_index, block_buffer.span());
m_fs.write_block(block_index, block_buffer);
}
return count;
@ -286,23 +217,22 @@ namespace Kernel
return {};
}
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
auto block_buffer = m_fs.get_block_buffer();
if (uint32_t rem = m_inode.size % block_size)
{
uint32_t last_block_index = TRY(data_block_index(current_data_blocks - 1));
uint32_t last_block_index = fs_block_of_data_block_index(current_data_blocks - 1);
m_fs.read_block(last_block_index, block_buffer.span());
m_fs.read_block(last_block_index, block_buffer);
memset(block_buffer.data() + rem, 0, block_size - rem);
m_fs.write_block(last_block_index, block_buffer.span());
m_fs.write_block(last_block_index, block_buffer);
}
memset(block_buffer.data(), 0, block_size);
while (blocks() < needed_data_blocks)
{
uint32_t block_index = TRY(allocate_new_block());
m_fs.write_block(block_index, block_buffer.span());
m_fs.write_block(block_index, block_buffer);
}
m_inode.size = new_size;
@ -324,12 +254,11 @@ namespace Kernel
}
const uint32_t block_size = blksize();
const uint32_t block_index = TRY(data_block_index(offset));
const uint32_t block_index = fs_block_of_data_block_index(offset);
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
auto block_buffer = m_fs.get_block_buffer();
m_fs.read_block(block_index, block_buffer.span());
m_fs.read_block(block_index, block_buffer);
// First determine if we have big enough list
{
@ -426,8 +355,8 @@ namespace Kernel
const uint32_t inode_index = TRY(m_fs.create_inode(ext2_inode));
const uint32_t block_size = m_fs.block_size();
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
auto block_buffer = m_fs.get_block_buffer();
auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len)
{
@ -462,8 +391,8 @@ namespace Kernel
goto needs_new_block;
// Try to insert inode to last data block
block_index = TRY(data_block_index(data_block_count - 1));
m_fs.read_block(block_index, block_buffer.span());
block_index = fs_block_of_data_block_index(data_block_count - 1);
m_fs.read_block(block_index, block_buffer);
while (entry_offset < block_size)
{
@ -476,7 +405,7 @@ namespace Kernel
if (entry.inode == 0 && needed_entry_len <= entry.rec_len)
{
write_inode(entry_offset, entry.rec_len);
m_fs.write_block(block_index, block_buffer.span());
m_fs.write_block(block_index, block_buffer);
return {};
}
else if (needed_entry_len <= entry.rec_len - entry_min_rec_len)
@ -485,7 +414,7 @@ namespace Kernel
entry.rec_len = entry_min_rec_len;
write_inode(entry_offset + entry.rec_len, new_rec_len);
m_fs.write_block(block_index, block_buffer.span());
m_fs.write_block(block_index, block_buffer);
return {};
}
@ -495,55 +424,132 @@ namespace Kernel
needs_new_block:
block_index = TRY(allocate_new_block());
m_fs.read_block(block_index, block_buffer.span());
m_fs.read_block(block_index, block_buffer);
write_inode(0, block_size);
m_fs.write_block(block_index, block_buffer.span());
m_fs.write_block(block_index, block_buffer);
return {};
}
#define READ_OR_ALLOCATE_BASE_BLOCK(index_) \
do { \
if (m_inode.block[index_] != 0) \
m_fs.read_block(m_inode.block[index_], block_buffer); \
else \
{ \
m_inode.block[index_] = TRY(m_fs.reserve_free_block(block_group())); \
memset(block_buffer.data(), 0x00, block_buffer.size()); \
} \
} while (false)
#define READ_OR_ALLOCATE_INDIRECT_BLOCK(result_, buffer_index_, parent_block_) \
uint32_t result_ = ((uint32_t*)block_buffer.data())[buffer_index_]; \
if (result_ != 0) \
m_fs.read_block(result_, block_buffer); \
else \
{ \
const uint32_t new_block_ = TRY(m_fs.reserve_free_block(block_group())); \
\
((uint32_t*)block_buffer.data())[buffer_index_] = new_block_; \
m_fs.write_block(parent_block_, block_buffer); \
\
result_ = new_block_; \
memset(block_buffer.data(), 0x00, block_buffer.size()); \
} \
do {} while (false)
#define WRITE_BLOCK_AND_RETURN(buffer_index_, parent_block_) \
do { \
const uint32_t block_ = TRY(m_fs.reserve_free_block(block_group())); \
\
ASSERT(((uint32_t*)block_buffer.data())[buffer_index_] == 0); \
((uint32_t*)block_buffer.data())[buffer_index_] = block_; \
m_fs.write_block(parent_block_, block_buffer); \
\
m_inode.blocks += blocks_per_fs_block; \
update_and_sync(); \
\
return block_; \
} while (false)
BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block()
{
uint32_t new_block_index = TRY(m_fs.reserve_free_block(block_group()));
auto set_index_func = [new_block_index] (uint32_t& index) { index = new_block_index; };
const uint32_t blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
const uint32_t blocks_per_data_block = blksize() / 512;
uint32_t block_array_index = blocks();
m_inode.blocks += blocks_per_data_block;
if (auto res = for_data_block_index(blocks() - 1, set_index_func, true); res.is_error())
auto update_and_sync =
[&]
{
if (mode().ifdir())
m_inode.size += blksize();
MUST(sync());
};
// direct block
if (block_array_index < 12)
{
m_inode.blocks -= blocks_per_data_block;
return res.release_error();
const uint32_t block = TRY(m_fs.reserve_free_block(block_group()));
ASSERT(m_inode.block[block_array_index] == 0);
m_inode.block[block_array_index] = block;
m_inode.blocks += blocks_per_fs_block;
update_and_sync();
return block;
}
if (mode().ifdir())
m_inode.size += blksize();
block_array_index -= 12;
TRY(sync());
return new_block_index;
auto block_buffer = m_fs.get_block_buffer();
// singly indirect block
if (block_array_index < indices_per_fs_block)
{
READ_OR_ALLOCATE_BASE_BLOCK(12);
WRITE_BLOCK_AND_RETURN(block_array_index, m_inode.block[12]);
}
block_array_index -= indices_per_fs_block;
// doubly indirect block
if (block_array_index < indices_per_fs_block * indices_per_fs_block)
{
READ_OR_ALLOCATE_BASE_BLOCK(13);
READ_OR_ALLOCATE_INDIRECT_BLOCK(direct_block, block_array_index / indices_per_fs_block, m_inode.block[13]);
WRITE_BLOCK_AND_RETURN(block_array_index % indices_per_fs_block, direct_block);
}
block_array_index -= indices_per_fs_block * indices_per_fs_block;
// triply indirect block
if (block_array_index < indices_per_fs_block * indices_per_fs_block * indices_per_fs_block)
{
dwarnln("here");
READ_OR_ALLOCATE_BASE_BLOCK(14);
READ_OR_ALLOCATE_INDIRECT_BLOCK(indirect_block, block_array_index / (indices_per_fs_block * indices_per_fs_block), 14);
READ_OR_ALLOCATE_INDIRECT_BLOCK(direct_block, (block_array_index / indices_per_fs_block) % indices_per_fs_block, indirect_block);
WRITE_BLOCK_AND_RETURN(block_array_index % indices_per_fs_block, direct_block);
}
ASSERT_NOT_REACHED();
}
#undef READ_OR_ALLOCATE_BASE_BLOCK
#undef READ_OR_ALLOCATE_INDIRECT_BLOCK
#undef WRITE_BLOCK_AND_RETURN
BAN::ErrorOr<void> Ext2Inode::sync()
{
auto inode_location_or_error = m_fs.locate_inode(ino());
if (inode_location_or_error.is_error())
{
dwarnln("Open inode not found from filesystem");
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
}
auto inode_location = m_fs.locate_inode(ino());
auto block_buffer = m_fs.get_block_buffer();
auto inode_location = inode_location_or_error.release_value();
const uint32_t block_size = blksize();
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
m_fs.read_block(inode_location.block, block_buffer.span());
m_fs.read_block(inode_location.block, block_buffer);
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)))
{
memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode));
m_fs.write_block(inode_location.block, block_buffer.span());
m_fs.write_block(inode_location.block, block_buffer);
}
return {};
@ -556,13 +562,12 @@ needs_new_block:
const uint32_t block_size = blksize();
const uint32_t data_block_count = blocks();
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
auto block_buffer = m_fs.get_block_buffer();
for (uint32_t i = 0; i < data_block_count; i++)
{
const uint32_t block_index = TRY(data_block_index(i));
m_fs.read_block(block_index, block_buffer.span());
const uint32_t block_index = fs_block_of_data_block_index(i);
m_fs.read_block(block_index, block_buffer);
const uint8_t* block_buffer_end = block_buffer.data() + block_size;
const uint8_t* entry_addr = block_buffer.data();

View File

@ -2,6 +2,7 @@
#include <BAN/ScopeGuard.h>
#include <BAN/UTF8.h>
#include <kernel/Font.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Process.h>
#include <fcntl.h>
@ -37,15 +38,12 @@ namespace Kernel
BAN::ErrorOr<Font> Font::load(BAN::StringView path)
{
int fd = TRY(Process::current().sys_open(path, O_RDONLY));
BAN::ScopeGuard _([fd] { MUST(Process::current().sys_close(fd)); });
struct stat st;
TRY(Process::current().sys_fstat(fd, &st));
auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
BAN::Vector<uint8_t> file_data;
TRY(file_data.resize(st.st_size));
TRY(Process::current().sys_read(fd, file_data.data(), st.st_size));
TRY(file_data.resize(inode->size()));
inode->read(0, file_data.data(), file_data.size());
if (file_data.size() < 4)
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);

View File

@ -12,9 +12,7 @@ extern uint8_t g_kernel_end[];
static constexpr size_t s_kmalloc_min_align = alignof(max_align_t);
static uint8_t s_kmalloc_storage[2 * MB];
static BAN::UniqPtr<Kernel::GeneralAllocator> s_general_allocator;
static uint8_t s_kmalloc_storage[20 * MB];
struct kmalloc_node
{
@ -303,19 +301,6 @@ void* kmalloc(size_t size, size_t align, bool force_indentity_map)
Kernel::CriticalScope critical;
// FIXME: this is a hack to make more dynamic kmalloc memory
if (size > PAGE_SIZE && !force_indentity_map)
{
using namespace Kernel;
if (!s_general_allocator)
s_general_allocator = MUST(GeneralAllocator::create(PageTable::kernel(), (vaddr_t)g_kernel_end));
auto vaddr = s_general_allocator->allocate(size);
if (vaddr)
return (void*)vaddr;
}
if (size == 0 || size >= info.size)
goto no_memory;
@ -350,9 +335,6 @@ void kfree(void* address)
Kernel::CriticalScope critical;
if (s_general_allocator && s_general_allocator->deallocate((Kernel::vaddr_t)address))
return;
if (s_kmalloc_fixed_info.base <= address_uint && address_uint < s_kmalloc_fixed_info.end)
{
auto& info = s_kmalloc_fixed_info;
@ -414,13 +396,6 @@ BAN::Optional<Kernel::paddr_t> kmalloc_paddr_of(Kernel::vaddr_t vaddr)
{
using namespace Kernel;
if (s_general_allocator)
{
auto paddr = s_general_allocator->paddr_of(vaddr);
if (paddr.has_value())
return paddr.value();
}
if ((vaddr_t)s_kmalloc_storage <= vaddr && vaddr < (vaddr_t)s_kmalloc_storage + sizeof(s_kmalloc_storage))
return V2P(vaddr);

View File

@ -247,6 +247,8 @@ namespace Kernel
{
LockGuard _(m_lock);
validate_pointer_access(termios, sizeof(::termios));
if (!m_controlling_terminal)
return BAN::Error::from_errno(ENOTTY);
@ -264,6 +266,8 @@ namespace Kernel
{
LockGuard _(m_lock);
validate_pointer_access(termios, sizeof(::termios));
if (!m_controlling_terminal)
return BAN::Error::from_errno(ENOTTY);
@ -360,12 +364,25 @@ namespace Kernel
// NOTE: We scope everything for automatic deletion
{
BAN::Vector<BAN::String> str_argv;
for (int i = 0; argv && argv[i]; i++)
TRY(str_argv.emplace_back(argv[i]));
BAN::Vector<BAN::String> str_envp;
for (int i = 0; envp && envp[i]; i++)
TRY(str_envp.emplace_back(envp[i]));
{
LockGuard _(m_lock);
for (int i = 0; argv && argv[i]; i++)
{
validate_pointer_access(argv + i, sizeof(char*));
validate_string_access(argv[i]);
TRY(str_argv.emplace_back(argv[i]));
}
for (int i = 0; envp && envp[i]; i++)
{
validate_pointer_access(envp + 1, sizeof(char*));
validate_string_access(envp[i]);
TRY(str_envp.emplace_back(envp[i]));
}
}
BAN::String working_directory;
@ -471,6 +488,11 @@ namespace Kernel
{
Process* target = nullptr;
{
LockGuard _(m_lock);
validate_pointer_access(stat_loc, sizeof(int));
}
// FIXME: support options
if (options)
return BAN::Error::from_errno(EINVAL);
@ -504,7 +526,12 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_nanosleep(const timespec* rqtp, timespec* rmtp)
{
(void)rmtp;
{
LockGuard _(m_lock);
validate_pointer_access(rqtp, sizeof(timespec));
validate_pointer_access(rmtp, sizeof(timespec));
}
// TODO: rmtp
SystemTimer::get().sleep(rqtp->tv_sec * 1000 + BAN::Math::div_round_up<uint64_t>(rqtp->tv_nsec, 1'000'000));
return 0;
}
@ -586,9 +613,8 @@ namespace Kernel
return {};
}
BAN::ErrorOr<long> Process::sys_open(BAN::StringView path, int flags, mode_t mode)
BAN::ErrorOr<long> Process::open_file(BAN::StringView path, int flags, mode_t mode)
{
LockGuard _(m_lock);
BAN::String absolute_path = TRY(absolute_path_of(path));
if (flags & O_CREAT)
@ -616,9 +642,18 @@ namespace Kernel
return fd;
}
BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags, mode_t mode)
BAN::ErrorOr<long> Process::sys_open(const char* path, int flags, mode_t mode)
{
LockGuard _(m_lock);
validate_string_access(path);
return open_file(path, flags, mode);
}
BAN::ErrorOr<long> Process::sys_openat(int fd, const char* path, int flags, mode_t mode)
{
LockGuard _(m_lock);
validate_string_access(path);
// FIXME: handle O_SEARCH in fd
@ -627,7 +662,7 @@ namespace Kernel
TRY(absolute_path.push_back('/'));
TRY(absolute_path.append(path));
return sys_open(absolute_path, flags, mode);
return open_file(absolute_path, flags, mode);
}
BAN::ErrorOr<long> Process::sys_close(int fd)
@ -640,18 +675,21 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count)
{
LockGuard _(m_lock);
validate_pointer_access(buffer, count);
return TRY(m_open_file_descriptors.read(fd, buffer, count));
}
BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count)
{
LockGuard _(m_lock);
validate_pointer_access(buffer, count);
return TRY(m_open_file_descriptors.write(fd, buffer, count));
}
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
{
LockGuard _(m_lock);
validate_pointer_access(fildes, sizeof(int) * 2);
TRY(m_open_file_descriptors.pipe(fildes));
return 0;
}
@ -699,16 +737,18 @@ namespace Kernel
return {};
}
BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* out)
BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* buf)
{
LockGuard _(m_lock);
TRY(m_open_file_descriptors.fstat(fd, out));
validate_pointer_access(buf, sizeof(struct stat));
TRY(m_open_file_descriptors.fstat(fd, buf));
return 0;
}
BAN::ErrorOr<long> Process::sys_fstatat(int fd, const char* path, struct stat* buf, int flag)
{
LockGuard _(m_lock);
validate_pointer_access(buf, sizeof(struct stat));
TRY(m_open_file_descriptors.fstatat(fd, path, buf, flag));
return 0;
}
@ -716,6 +756,7 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_stat(const char* path, struct stat* buf, int flag)
{
LockGuard _(m_lock);
validate_pointer_access(buf, sizeof(struct stat));
TRY(m_open_file_descriptors.stat(TRY(absolute_path_of(path)), buf, flag));
return 0;
}
@ -741,6 +782,7 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size)
{
LockGuard _(m_lock);
validate_pointer_access(list, list_size);
TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size));
return 0;
}
@ -751,6 +793,7 @@ namespace Kernel
{
LockGuard _(m_lock);
validate_string_access(path);
absolute_path = TRY(absolute_path_of(path));
}
@ -768,6 +811,8 @@ namespace Kernel
{
LockGuard _(m_lock);
validate_pointer_access(buffer, size);
if (size < m_working_directory.size() + 1)
return BAN::Error::from_errno(ERANGE);
@ -777,32 +822,37 @@ namespace Kernel
return (long)buffer;
}
BAN::ErrorOr<long> Process::sys_mmap(const sys_mmap_t& args)
BAN::ErrorOr<long> Process::sys_mmap(const sys_mmap_t* args)
{
if (args.prot != PROT_NONE && args.prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
{
LockGuard _(m_lock);
validate_pointer_access(args, sizeof(sys_mmap_t));
}
if (args->prot != PROT_NONE && args->prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return BAN::Error::from_errno(EINVAL);
PageTable::flags_t flags = PageTable::Flags::UserSupervisor;
if (args.prot & PROT_READ)
if (args->prot & PROT_READ)
flags |= PageTable::Flags::Present;
if (args.prot & PROT_WRITE)
if (args->prot & PROT_WRITE)
flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
if (args.prot & PROT_EXEC)
if (args->prot & PROT_EXEC)
flags |= PageTable::Flags::Execute | PageTable::Flags::Present;
if (args.flags == (MAP_ANONYMOUS | MAP_PRIVATE))
if (args->flags == (MAP_ANONYMOUS | MAP_PRIVATE))
{
if (args.addr != nullptr)
if (args->addr != nullptr)
return BAN::Error::from_errno(ENOTSUP);
if (args.off != 0)
if (args->off != 0)
return BAN::Error::from_errno(EINVAL);
if (args.len % PAGE_SIZE != 0)
if (args->len % PAGE_SIZE != 0)
return BAN::Error::from_errno(EINVAL);
auto range = TRY(VirtualRange::create_to_vaddr_range(
page_table(),
0x400000, KERNEL_OFFSET,
args.len,
args->len,
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
));
range->set_zero();
@ -839,10 +889,12 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_termid(char* buffer) const
BAN::ErrorOr<long> Process::sys_termid(char* buffer)
{
LockGuard _(m_lock);
validate_string_access(buffer);
auto& tty = m_controlling_terminal;
if (!tty)
@ -857,8 +909,13 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_clock_gettime(clockid_t clock_id, timespec* tp) const
BAN::ErrorOr<long> Process::sys_clock_gettime(clockid_t clock_id, timespec* tp)
{
{
LockGuard _(m_lock);
validate_pointer_access(tp, sizeof(timespec));
}
switch (clock_id)
{
case CLOCK_MONOTONIC:
@ -882,6 +939,11 @@ namespace Kernel
if (signal < _SIGMIN || signal > _SIGMAX)
return BAN::Error::from_errno(EINVAL);
{
LockGuard _(m_lock);
validate_pointer_access((void*)handler, sizeof(handler));
}
CriticalScope _;
m_signal_handlers[signal] = (vaddr_t)handler;
return 0;
@ -1264,4 +1326,43 @@ namespace Kernel
return absolute_path;
}
void Process::validate_string_access(const char* str)
{
// NOTE: we will page fault here, if str is not actually mapped
// outcome is still the same; SIGSEGV
validate_pointer_access(str, strlen(str) + 1);
}
void Process::validate_pointer_access(const void* ptr, size_t size)
{
ASSERT(&Process::current() == this);
auto& thread = Thread::current();
vaddr_t vaddr = (vaddr_t)ptr;
// NOTE: detect overflow
if (vaddr + size < vaddr)
goto unauthorized_access;
// trying to access kernel space memory
if (vaddr + size > KERNEL_OFFSET)
goto unauthorized_access;
if (vaddr == 0)
return;
if (vaddr >= thread.stack_base() && vaddr + size <= thread.stack_base() + thread.stack_size())
return;
// FIXME: should we allow cross mapping access?
for (auto& mapped_range : m_mapped_ranges)
if (vaddr >= mapped_range.range->vaddr() && vaddr + size <= mapped_range.range->vaddr() + mapped_range.range->size())
return;
unauthorized_access:
dwarnln("process {}, thread {} attempted to make an invalid pointer access", pid(), Thread::current().tid());
Debug::dump_stack_trace();
MUST(sys_raise(SIGSEGV));
}
}

View File

@ -188,7 +188,7 @@ namespace Kernel
ret = Process::current().sys_sync();
break;
case SYS_MMAP:
ret = Process::current().sys_mmap(*(const sys_mmap_t*)arg1);
ret = Process::current().sys_mmap((const sys_mmap_t*)arg1);
break;
case SYS_MUNMAP:
ret = Process::current().sys_munmap((void*)arg1, (size_t)arg2);

View File

@ -3,6 +3,7 @@
#include <BAN/UTF8.h>
#include <kernel/Debug.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h>
#include <kernel/Process.h>
#include <kernel/Terminal/TTY.h>
@ -49,11 +50,12 @@ namespace Kernel
Process::create_kernel(
[](void*)
{
int fd = MUST(Process::current().sys_open("/dev/input0"sv, O_RDONLY));
auto inode = MUST(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/input0"sv, O_RDONLY)).inode;
while (true)
{
Input::KeyEvent event;
ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event));
size_t read = MUST(inode->read(0, &event, sizeof(event)));
ASSERT(read == sizeof(event));
TTY::current()->on_key_event(event);
}
}, nullptr