Compare commits

..

No commits in common. "f2e41f71d6fb7b8e0cbc836c3fd1be8ce13b9f73" and "34e680d79209fd83d1f92080e7ae71e0d445ca6d" have entirely different histories.

17 changed files with 260 additions and 605 deletions

View File

@ -3,7 +3,8 @@
#include <BAN/UniqPtr.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/Memory/Types.h>
#include <kernel/ThreadBlocker.h>
#include <stddef.h>
namespace Kernel
{
@ -41,10 +42,6 @@ namespace Kernel
size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); }
size_t physical_page_count() const { return m_physical_page_count; }
void pin() { m_pinned_count++; }
void unpin() { if (--m_pinned_count == 0) m_pinned_blocker.unblock(); }
void wait_not_pinned() { while (m_pinned_count) m_pinned_blocker.block_with_timeout_ms(100); }
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
// Returns error if no memory was available
@ -67,9 +64,6 @@ namespace Kernel
const PageTable::flags_t m_flags;
vaddr_t m_vaddr { 0 };
size_t m_physical_page_count { 0 };
BAN::Atomic<size_t> m_pinned_count { 0 };
ThreadBlocker m_pinned_blocker;
};
}

View File

@ -51,7 +51,7 @@ namespace Kernel
BAN::ErrorOr<size_t> sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<VirtualFileSystem::File> file_of(int) const;
BAN::ErrorOr<BAN::String> path_of(int) const;
BAN::ErrorOr<BAN::StringView> path_of(int) const;
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
BAN::ErrorOr<int> status_flags_of(int) const;
@ -98,7 +98,6 @@ namespace Kernel
private:
const Credentials& m_credentials;
mutable Mutex m_mutex;
BAN::Array<OpenFile, OPEN_MAX> m_open_files;
};

View File

@ -241,7 +241,6 @@ namespace Kernel
BAN::ErrorOr<void> validate_string_access(const char*);
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
uint64_t signal_pending_mask() const
{

View File

@ -53,8 +53,7 @@ namespace Kernel
// Returns true if pending signal can be added to thread
bool can_add_signal_to_execute() const;
bool will_execute_signal() const;
// Returns true if handled signal had SA_RESTART
bool handle_signal(int signal = 0);
void handle_signal(int signal = 0);
bool add_signal(int signal);
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout

View File

@ -13,7 +13,6 @@ namespace Kernel
MemoryRegion::~MemoryRegion()
{
ASSERT(m_pinned_count == 0);
if (m_vaddr)
m_page_table.unmap_range(m_vaddr, m_size);
}

View File

@ -60,10 +60,7 @@ namespace Kernel
{
auto& connection_info = m_info.get<ConnectionInfo>();
if (auto connection = connection_info.connection.lock(); connection && connection->m_info.has<ConnectionInfo>())
{
connection->m_info.get<ConnectionInfo>().target_closed = true;
connection->m_packet_thread_blocker.unblock();
}
}
}
@ -354,19 +351,19 @@ namespace Kernel
BAN::ErrorOr<size_t> UnixDomainSocket::recvfrom_impl(BAN::ByteSpan buffer, sockaddr*, socklen_t*)
{
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
bool expected = true;
if (connection_info.target_closed.compare_exchange(expected, false))
return 0;
if (!connection_info.connection)
return BAN::Error::from_errno(ENOTCONN);
}
auto state = m_packet_lock.lock();
while (m_packet_size_total == 0)
{
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
bool expected = true;
if (connection_info.target_closed.compare_exchange(expected, false))
return 0;
if (!connection_info.connection)
return BAN::Error::from_errno(ENOTCONN);
}
m_packet_lock.unlock(state);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker));
state = m_packet_lock.lock();

View File

@ -23,7 +23,6 @@ namespace Kernel
OpenFileDescriptorSet& OpenFileDescriptorSet::operator=(OpenFileDescriptorSet&& other)
{
LockGuard _(m_mutex);
for (size_t i = 0; i < m_open_files.size(); i++)
m_open_files[i] = BAN::move(other.m_open_files[i]);
return *this;
@ -31,8 +30,6 @@ namespace Kernel
BAN::ErrorOr<void> OpenFileDescriptorSet::clone_from(const OpenFileDescriptorSet& other)
{
LockGuard _(m_mutex);
close_all();
for (int fd = 0; fd < (int)other.m_open_files.size(); fd++)
@ -70,11 +67,11 @@ namespace Kernel
if ((flags & O_TRUNC) && (flags & O_WRONLY) && file.inode->mode().ifreg())
TRY(file.inode->truncate(0));
LockGuard _(m_mutex);
constexpr int status_mask = O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC | O_ACCMODE;
int fd = TRY(get_free_fd());
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(BAN::move(file), 0, flags & status_mask));
m_open_files[fd].descriptor_flags = flags & O_CLOEXEC;
return fd;
}
@ -138,7 +135,6 @@ namespace Kernel
auto socket = TRY(NetworkManager::get().create_socket(sock_domain, sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
LockGuard _(m_mutex);
int fd = TRY(get_free_fd());
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, "<socket>"_sv), 0, O_RDWR | status_flags));
m_open_files[fd].descriptor_flags = descriptor_flags;
@ -147,8 +143,6 @@ namespace Kernel
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
{
LockGuard _(m_mutex);
TRY(get_free_fd_pair(fds));
auto pipe = TRY(Pipe::create(m_credentials));
@ -165,8 +159,6 @@ namespace Kernel
if (fildes2 < 0 || fildes2 >= (int)m_open_files.size())
return BAN::Error::from_errno(EBADF);
LockGuard _(m_mutex);
TRY(validate_fd(fildes));
if (fildes == fildes2)
return fildes;
@ -187,8 +179,6 @@ namespace Kernel
BAN::ErrorOr<int> OpenFileDescriptorSet::fcntl(int fd, int cmd, int extra)
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
switch (cmd)
@ -233,8 +223,6 @@ namespace Kernel
BAN::ErrorOr<off_t> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
off_t base_offset;
@ -264,22 +252,18 @@ namespace Kernel
BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
return m_open_files[fd].offset();
}
BAN::ErrorOr<void> OpenFileDescriptorSet::truncate(int fd, off_t length)
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
return m_open_files[fd].inode()->truncate(length);
}
BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd)
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
if (m_open_files[fd].path() == "<pipe wr>"_sv)
@ -296,14 +280,12 @@ namespace Kernel
void OpenFileDescriptorSet::close_all()
{
LockGuard _(m_mutex);
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
(void)close(fd);
}
void OpenFileDescriptorSet::close_cloexec()
{
LockGuard _(m_mutex);
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
{
if (validate_fd(fd).is_error())
@ -315,155 +297,83 @@ namespace Kernel
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read(int fd, BAN::ByteSpan buffer)
{
BAN::RefPtr<Inode> inode;
bool is_nonblock;
off_t offset;
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (open_file.inode()->mode().ifsock())
return recvfrom(fd, buffer, nullptr, nullptr);
if (!(open_file.status_flags() & O_RDONLY))
return BAN::Error::from_errno(EBADF);
inode = open_file.inode();
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
offset = open_file.offset();
}
if (inode->mode().ifsock())
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (open_file.inode()->mode().ifsock())
return recvfrom(fd, buffer, nullptr, nullptr);
size_t nread;
{
LockGuard _(inode->m_mutex);
if (is_nonblock && !inode->can_read())
return 0;
nread = TRY(inode->read(offset, buffer));
}
LockGuard _(m_mutex);
// NOTE: race condition with offset, its UB per POSIX
if (!validate_fd(fd).is_error())
m_open_files[fd].offset() = offset + nread;
if (!(open_file.status_flags() & O_RDONLY))
return BAN::Error::from_errno(EBADF);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
return 0;
const size_t nread = TRY(open_file.inode()->read(open_file.offset(), buffer));
open_file.offset() += nread;
return nread;
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::write(int fd, BAN::ConstByteSpan buffer)
{
BAN::RefPtr<Inode> inode;
bool is_nonblock;
off_t offset;
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!(open_file.status_flags() & O_WRONLY))
return BAN::Error::from_errno(EBADF);
inode = open_file.inode();
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
offset = (open_file.status_flags() & O_APPEND) ? inode->size() : open_file.offset();
}
if (inode->mode().ifsock())
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (open_file.inode()->mode().ifsock())
return sendto(fd, buffer, nullptr, 0);
size_t nwrite;
{
LockGuard _(inode->m_mutex);
if (is_nonblock && !inode->can_write())
return BAN::Error::from_errno(EWOULDBLOCK);
nwrite = TRY(inode->write(offset, buffer));
}
LockGuard _(m_mutex);
// NOTE: race condition with offset, its UB per POSIX
if (!validate_fd(fd).is_error())
m_open_files[fd].offset() = offset + nwrite;
if (!(open_file.status_flags() & O_WRONLY))
return BAN::Error::from_errno(EBADF);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
return BAN::Error::from_errno(EWOULDBLOCK);
if (open_file.status_flags() & O_APPEND)
open_file.offset() = open_file.inode()->size();
const size_t nwrite = TRY(open_file.inode()->write(open_file.offset(), buffer));
open_file.offset() += nwrite;
return nwrite;
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read_dir_entries(int fd, struct dirent* list, size_t list_len)
{
BAN::RefPtr<Inode> inode;
off_t offset;
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!(open_file.status_flags() & O_RDONLY))
return BAN::Error::from_errno(EACCES);
inode = open_file.inode();
offset = open_file.offset();
}
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!(open_file.status_flags() & O_RDONLY))
return BAN::Error::from_errno(EACCES);
for (;;)
{
auto ret = inode->list_next_inodes(offset, list, list_len);
auto ret = open_file.inode()->list_next_inodes(open_file.offset(), list, list_len);
if (ret.is_error() && ret.error().get_error_code() != ENODATA)
return ret;
offset++;
open_file.offset()++;
if (ret.is_error())
continue;
LockGuard _(m_mutex);
// NOTE: race condition with offset, its UB per POSIX
if (!validate_fd(fd).is_error())
m_open_files[fd].offset() = offset;
return ret;
}
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len)
{
BAN::RefPtr<Inode> inode;
bool is_nonblock;
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!open_file.inode()->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
inode = open_file.inode();
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
}
LockGuard _(inode->m_mutex);
if (is_nonblock && !inode->can_read())
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!open_file.inode()->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
LockGuard _(open_file.inode()->m_mutex);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read())
return BAN::Error::from_errno(EWOULDBLOCK);
return inode->recvfrom(buffer, address, address_len);
return open_file.inode()->recvfrom(buffer, address, address_len);
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len)
{
BAN::RefPtr<Inode> inode;
bool is_nonblock;
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!open_file.inode()->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
inode = open_file.inode();
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
}
LockGuard _(inode->m_mutex);
if (is_nonblock && !inode->can_write())
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
if (!open_file.inode()->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
return BAN::Error::from_errno(EWOULDBLOCK);
LockGuard _(open_file.inode()->m_mutex);
size_t total_sent = 0;
while (total_sent < buffer.size())
{
if (is_nonblock && !inode->can_write())
if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write())
return total_sent;
const size_t nsend = TRY(inode->sendto(buffer.slice(total_sent), address, address_len));
const size_t nsend = TRY(open_file.inode()->sendto(buffer.slice(total_sent), address, address_len));
if (nsend == 0)
return 0;
total_sent += nsend;
@ -474,37 +384,30 @@ namespace Kernel
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
return TRY(m_open_files[fd].description->file.clone());
}
BAN::ErrorOr<BAN::String> OpenFileDescriptorSet::path_of(int fd) const
BAN::ErrorOr<BAN::StringView> OpenFileDescriptorSet::path_of(int fd) const
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
BAN::String path;
TRY(path.append(m_open_files[fd].path()));
return path;
return m_open_files[fd].path();
}
BAN::ErrorOr<BAN::RefPtr<Inode>> OpenFileDescriptorSet::inode_of(int fd)
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
return m_open_files[fd].inode();
}
BAN::ErrorOr<int> OpenFileDescriptorSet::status_flags_of(int fd) const
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
return m_open_files[fd].status_flags();
}
BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const
{
LockGuard _(m_mutex);
if (fd < 0 || fd >= (int)m_open_files.size())
return BAN::Error::from_errno(EBADF);
if (!m_open_files[fd].description)
@ -514,7 +417,6 @@ namespace Kernel
BAN::ErrorOr<int> OpenFileDescriptorSet::get_free_fd() const
{
LockGuard _(m_mutex);
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
if (!m_open_files[fd].description)
return fd;
@ -523,7 +425,6 @@ namespace Kernel
BAN::ErrorOr<void> OpenFileDescriptorSet::get_free_fd_pair(int fds[2]) const
{
LockGuard _(m_mutex);
size_t found = 0;
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
{

View File

@ -1051,36 +1051,28 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_close(int fd)
{
LockGuard _(m_process_lock);
TRY(m_open_file_descriptors.close(fd));
return 0;
}
BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count)
{
LockGuard _(m_process_lock);
if (count == 0)
{
TRY(m_open_file_descriptors.inode_of(fd));
return 0;
}
// FIXME: buffer_region can be null as stack is not MemoryRegion
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
BAN::ScopeGuard _([&] { if (buffer_region) buffer_region->unpin(); });
return TRY(m_open_file_descriptors.read(fd, BAN::ByteSpan(static_cast<uint8_t*>(buffer), count)));
TRY(validate_pointer_access(buffer, count, true));
return TRY(m_open_file_descriptors.read(fd, BAN::ByteSpan((uint8_t*)buffer, count)));
}
BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count)
{
if (count == 0)
{
TRY(m_open_file_descriptors.inode_of(fd));
return 0;
}
// FIXME: buffer_region can be null as stack is not MemoryRegion
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, false));
BAN::ScopeGuard _([&] { if (buffer_region) buffer_region->unpin(); });
return TRY(m_open_file_descriptors.write(fd, BAN::ConstByteSpan(static_cast<const uint8_t*>(buffer), count)));
LockGuard _(m_process_lock);
TRY(validate_pointer_access(buffer, count, false));
return TRY(m_open_file_descriptors.write(fd, BAN::ByteSpan((uint8_t*)buffer, count)));
}
BAN::ErrorOr<long> Process::sys_access(const char* path, int amode)
@ -1304,24 +1296,19 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_accept(int socket, sockaddr* address, socklen_t* address_len, int flags)
{
if (!address != !address_len)
if (address && !address_len)
return BAN::Error::from_errno(EINVAL);
if (!address && address_len)
return BAN::Error::from_errno(EINVAL);
if (flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC))
return BAN::Error::from_errno(EINVAL);
MemoryRegion* address_region1 = nullptr;
MemoryRegion* address_region2 = nullptr;
BAN::ScopeGuard _([&] {
if (address_region1)
address_region1->unpin();
if (address_region2)
address_region2->unpin();
});
address_region1 = TRY(validate_and_pin_pointer_access(address_len, sizeof(address_len), true));
const socklen_t address_len_safe = address_len ? *address_len : 0;
address_region2 = TRY(validate_and_pin_pointer_access(address, address_len_safe, true));
LockGuard _(m_process_lock);
if (address)
{
TRY(validate_pointer_access(address_len, sizeof(*address_len), true));
TRY(validate_pointer_access(address, *address_len, true));
}
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
if (!inode->mode().ifsock())
@ -1351,13 +1338,13 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_connect(int socket, const sockaddr* address, socklen_t address_len)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(address, address_len, false));
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
if (!inode->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
auto* address_region = TRY(validate_and_pin_pointer_access(address, address_len, true));
BAN::ScopeGuard _([&] { if (address_region) address_region->unpin(); });
TRY(inode->connect(address, address_len));
return 0;
}
@ -1374,69 +1361,35 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_sendto(const sys_sendto_t* _arguments)
BAN::ErrorOr<long> Process::sys_sendto(const sys_sendto_t* arguments)
{
sys_sendto_t arguments;
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(_arguments, sizeof(sys_sendto_t), false));
arguments = *_arguments;
}
LockGuard _(m_process_lock);
TRY(validate_pointer_access(arguments, sizeof(sys_sendto_t), false));
TRY(validate_pointer_access(arguments->message, arguments->length, false));
TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len, false));
if (arguments.length == 0)
return BAN::Error::from_errno(EINVAL);
MemoryRegion* message_region = nullptr;
MemoryRegion* address_region = nullptr;
BAN::ScopeGuard _([&] {
if (message_region)
message_region->unpin();
if (address_region)
address_region->unpin();
});
message_region = TRY(validate_and_pin_pointer_access(arguments.message, arguments.length, false));
address_region = TRY(validate_and_pin_pointer_access(arguments.dest_addr, arguments.dest_len, false));
auto message = BAN::ConstByteSpan(static_cast<const uint8_t*>(arguments.message), arguments.length);
return TRY(m_open_file_descriptors.sendto(arguments.socket, message, arguments.dest_addr, arguments.dest_len));
auto message = BAN::ConstByteSpan(static_cast<const uint8_t*>(arguments->message), arguments->length);
return TRY(m_open_file_descriptors.sendto(arguments->socket, message, arguments->dest_addr, arguments->dest_len));
}
BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* _arguments)
BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* arguments)
{
sys_recvfrom_t arguments;
if (arguments->address && !arguments->address_len)
return BAN::Error::from_errno(EINVAL);
if (!arguments->address && arguments->address_len)
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_process_lock);
TRY(validate_pointer_access(arguments, sizeof(sys_recvfrom_t), false));
TRY(validate_pointer_access(arguments->buffer, arguments->length, true));
if (arguments->address)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(_arguments, sizeof(sys_sendto_t), false));
arguments = *_arguments;
TRY(validate_pointer_access(arguments->address_len, sizeof(*arguments->address_len), true));
TRY(validate_pointer_access(arguments->address, *arguments->address_len, true));
}
if (!arguments.address != !arguments.address_len)
return BAN::Error::from_errno(EINVAL);
if (arguments.length == 0)
return BAN::Error::from_errno(EINVAL);
MemoryRegion* buffer_region = nullptr;
MemoryRegion* address_region1 = nullptr;
MemoryRegion* address_region2 = nullptr;
BAN::ScopeGuard _([&] {
if (buffer_region)
buffer_region->unpin();
if (address_region1)
address_region1->unpin();
if (address_region2)
address_region2->unpin();
});
buffer_region = TRY(validate_and_pin_pointer_access(arguments.buffer, arguments.length, true));
address_region1 = TRY(validate_and_pin_pointer_access(arguments.address_len, sizeof(*arguments.address_len), true));
const socklen_t address_len_safe = arguments.address_len ? *arguments.address_len : 0;
address_region2 = TRY(validate_and_pin_pointer_access(arguments.address, address_len_safe, true));
auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments.buffer), arguments.length);
return TRY(m_open_file_descriptors.recvfrom(arguments.socket, message, arguments.address, arguments.address_len));
auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments->buffer), arguments->length);
return TRY(m_open_file_descriptors.recvfrom(arguments->socket, message, arguments->address, arguments->address_len));
}
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)
@ -1446,56 +1399,37 @@ namespace Kernel
return TRY(inode->ioctl(request, arg));
}
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* _arguments)
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* arguments)
{
sys_pselect_t arguments;
LockGuard _(m_process_lock);
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(_arguments, sizeof(sys_pselect_t), false));
arguments = *_arguments;
}
MemoryRegion* readfd_region = nullptr;
MemoryRegion* writefd_region = nullptr;
MemoryRegion* errorfd_region = nullptr;
MemoryRegion* timeout_region = nullptr;
MemoryRegion* sigmask_region = nullptr;
BAN::ScopeGuard _([&] {
if (readfd_region)
readfd_region->unpin();
if (writefd_region)
writefd_region->unpin();
if (errorfd_region)
errorfd_region->unpin();
if (timeout_region)
timeout_region->unpin();
if (sigmask_region)
sigmask_region->unpin();
});
readfd_region = TRY(validate_and_pin_pointer_access(arguments.readfds, sizeof(fd_set), true));
writefd_region = TRY(validate_and_pin_pointer_access(arguments.writefds, sizeof(fd_set), true));
errorfd_region = TRY(validate_and_pin_pointer_access(arguments.errorfds, sizeof(fd_set), true));
timeout_region = TRY(validate_and_pin_pointer_access(arguments.timeout, sizeof(timespec), false));
sigmask_region = TRY(validate_and_pin_pointer_access(arguments.sigmask, sizeof(sigset_t), false));
TRY(validate_pointer_access(arguments, sizeof(sys_pselect_t), false));
if (arguments->readfds)
TRY(validate_pointer_access(arguments->readfds, sizeof(fd_set), true));
if (arguments->writefds)
TRY(validate_pointer_access(arguments->writefds, sizeof(fd_set), true));
if (arguments->errorfds)
TRY(validate_pointer_access(arguments->errorfds, sizeof(fd_set), true));
if (arguments->timeout)
TRY(validate_pointer_access(arguments->timeout, sizeof(timespec), false));
if (arguments->sigmask)
TRY(validate_pointer_access(arguments->sigmask, sizeof(sigset_t), false));
const auto old_sigmask = Thread::current().m_signal_block_mask;
if (arguments.sigmask)
Thread::current().m_signal_block_mask = *arguments.sigmask;
if (arguments->sigmask)
Thread::current().m_signal_block_mask = *arguments->sigmask;
BAN::ScopeGuard sigmask_restore([old_sigmask] { Thread::current().m_signal_block_mask = old_sigmask; });
uint64_t timedout_ns = SystemTimer::get().ns_since_boot();
if (arguments.timeout)
if (arguments->timeout)
{
timedout_ns += arguments.timeout->tv_sec * 1'000'000'000;
timedout_ns += arguments.timeout->tv_nsec;
timedout_ns += arguments->timeout->tv_sec * 1'000'000'000;
timedout_ns += arguments->timeout->tv_nsec;
}
fd_set readfds; FD_ZERO(&readfds);
fd_set writefds; FD_ZERO(&writefds);
fd_set errorfds; FD_ZERO(&errorfds);
fd_set readfds; FD_ZERO(&readfds);
fd_set writefds; FD_ZERO(&writefds);
fd_set errorfds; FD_ZERO(&errorfds);
int set_bits = 0;
for (;;)
@ -1521,38 +1455,38 @@ namespace Kernel
}
};
for (int i = 0; i < arguments.nfds; i++)
for (int i = 0; i < arguments->nfds; i++)
{
update_fds(i, arguments.readfds, &readfds, &Inode::can_read);
update_fds(i, arguments.writefds, &writefds, &Inode::can_write);
update_fds(i, arguments.errorfds, &errorfds, &Inode::has_error);
update_fds(i, arguments->readfds, &readfds, &Inode::can_read);
update_fds(i, arguments->writefds, &writefds, &Inode::can_write);
update_fds(i, arguments->errorfds, &errorfds, &Inode::has_error);
}
if (set_bits > 0)
break;
if (arguments.timeout && SystemTimer::get().ns_since_boot() >= timedout_ns)
if (arguments->timeout && SystemTimer::get().ns_since_boot() >= timedout_ns)
break;
// FIXME: implement some multi thread blocker system?
LockFreeGuard free(m_process_lock);
TRY(Thread::current().sleep_or_eintr_ms(1));
}
if (arguments.readfds)
FD_ZERO(arguments.readfds);
if (arguments.writefds)
FD_ZERO(arguments.writefds);
if (arguments.errorfds)
FD_ZERO(arguments.errorfds);
if (arguments->readfds)
FD_ZERO(arguments->readfds);
if (arguments->writefds)
FD_ZERO(arguments->writefds);
if (arguments->errorfds)
FD_ZERO(arguments->errorfds);
for (int i = 0; i < arguments.nfds; i++)
for (int i = 0; i < arguments->nfds; i++)
{
if (arguments.readfds && FD_ISSET(i, &readfds))
FD_SET(i, arguments.readfds);
if (arguments.writefds && FD_ISSET(i, &writefds))
FD_SET(i, arguments.writefds);
if (arguments.errorfds && FD_ISSET(i, &errorfds))
FD_SET(i, arguments.errorfds);
if (arguments->readfds && FD_ISSET(i, &readfds))
FD_SET(i, arguments->readfds);
if (arguments->writefds && FD_ISSET(i, &writefds))
FD_SET(i, arguments->writefds);
if (arguments->errorfds && FD_ISSET(i, &errorfds))
FD_SET(i, arguments->errorfds);
}
return set_bits;
@ -1872,10 +1806,7 @@ namespace Kernel
const vaddr_t region_s = region->vaddr();
const vaddr_t region_e = region->vaddr() + region->size();
if (vaddr <= region_s && region_e <= vaddr + len)
{
region->wait_not_pinned();
m_mapped_regions.remove(i--);
}
else if (region->overlaps(vaddr, len))
dwarnln("TODO: partial region munmap");
}
@ -2142,7 +2073,9 @@ namespace Kernel
if (act)
{
if (act->sa_flags & ~(SA_RESTART))
if (act->sa_flags == SA_RESTART)
dwarnln("FIXME: sigaction ignoring SA_RESTART", signal, act->sa_flags);
else if (act->sa_flags)
{
dwarnln("TODO: sigaction({}, {H})", signal, act->sa_flags);
return BAN::Error::from_errno(ENOTSUP);
@ -2750,19 +2683,4 @@ unauthorized_access:
return {};
}
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(ptr, size, needs_write));
for (auto& region : m_mapped_regions)
{
if (!region->contains_fully(reinterpret_cast<vaddr_t>(ptr), size))
continue;
region->pin();
return region.ptr();
}
// FIXME: Make stack MemoryRegion?
return nullptr;
}
}

View File

@ -79,9 +79,7 @@ namespace Kernel
auto& current_thread = Thread::current();
if (current_thread.can_add_signal_to_execute())
if (current_thread.handle_signal())
if (ret.is_error() && ret.error().get_error_code() == EINTR)
ret = BAN::Error::from_errno(ERESTART);
current_thread.handle_signal();
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);

View File

@ -435,7 +435,7 @@ namespace Kernel
return interrupt_stack.ip == (uintptr_t)signal_trampoline;
}
bool Thread::handle_signal(int signal)
void Thread::handle_signal(int signal)
{
ASSERT(&Thread::current() == this);
ASSERT(is_userspace());
@ -463,12 +463,10 @@ namespace Kernel
}
vaddr_t signal_handler;
bool has_sa_restart;
{
SpinLockGuard _(m_process->m_signal_lock);
ASSERT(!(m_process->m_signal_handlers[signal].sa_flags & SA_SIGINFO));
signal_handler = (vaddr_t)m_process->m_signal_handlers[signal].sa_handler;
has_sa_restart = !!(m_process->m_signal_handlers[signal].sa_flags & SA_RESTART);
}
m_signal_pending_mask &= ~(1ull << signal);
@ -536,8 +534,6 @@ namespace Kernel
ASSERT_NOT_REACHED();
}
}
return has_sa_restart;
}
bool Thread::add_signal(int signal)

View File

@ -90,7 +90,6 @@ __BEGIN_DECLS
#define EXDEV 81
#define ENOTBLK 82
#define ERESTART 0xFE /* internal errno for SA_RESTART */
#define EUNKNOWN 0xFF
#define errno (*__errno_location())

View File

@ -107,7 +107,7 @@ int getaddrinfo(const char* __restrict nodename, const char* __restrict servname
goto error_close_socket;
sockaddr_storage storage;
if (recv(resolver_sock, &storage, sizeof(storage), 0) < static_cast<ssize_t>(sizeof(sockaddr_in)))
if (recv(resolver_sock, &storage, sizeof(storage), 0) == -1)
goto error_close_socket;
close(resolver_sock);
@ -115,12 +115,12 @@ int getaddrinfo(const char* __restrict nodename, const char* __restrict servname
if (storage.ss_family != AF_INET)
return EAI_FAIL;
ipv4_addr = reinterpret_cast<sockaddr_in&>(storage).sin_addr.s_addr;
ipv4_addr = *reinterpret_cast<in_addr_t*>(storage.ss_storage);
}
{
addrinfo* ai = (addrinfo*)malloc(sizeof(addrinfo) + sizeof(sockaddr_in));
if (ai == nullptr)
if (*res == nullptr)
return EAI_MEMORY;
sockaddr_in* sa_in = reinterpret_cast<sockaddr_in*>(reinterpret_cast<uintptr_t>(ai) + sizeof(addrinfo));
@ -193,7 +193,7 @@ struct hostent* gethostbyname(const char* name)
goto error_close_socket;
sockaddr_storage storage;
if (recv(socket, &storage, sizeof(storage), 0) < static_cast<ssize_t>(sizeof(sockaddr_in)))
if (recv(socket, &storage, sizeof(storage), 0) == -1)
goto error_close_socket;
close(socket);
@ -201,7 +201,7 @@ struct hostent* gethostbyname(const char* name)
if (storage.ss_family != AF_INET)
return nullptr;
addr_buffer = reinterpret_cast<sockaddr_in&>(storage).sin_addr.s_addr;
addr_buffer = *reinterpret_cast<in_addr_t*>(storage.ss_storage);
}
return &hostent;

View File

@ -83,10 +83,7 @@ long syscall(long syscall, ...)
va_end(args);
long ret;
do
ret = Kernel::syscall(syscall, arg1, arg2, arg3, arg4, arg5);
while (ret == -ERESTART);
long ret = Kernel::syscall(syscall, arg1, arg2, arg3, arg4, arg5);
if (ret < 0)
{

View File

@ -1,7 +1,10 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define MAX(a, b) ((a) < (b) ? (b) : (a))
@ -13,37 +16,39 @@ int main(int argc, char** argv)
return 1;
}
const addrinfo hints {
.ai_flags = 0,
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0,
.ai_addrlen = 0,
.ai_addr = nullptr,
.ai_canonname = nullptr,
.ai_next = nullptr,
};
addrinfo* result;
if (int ret = getaddrinfo(argv[1], nullptr, &hints, &result); ret != 0)
int socket = ::socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (socket == -1)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
perror("socket");
return 1;
}
for (addrinfo* ai = result; ai; ai = ai->ai_next)
sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/resolver.sock");
if (connect(socket, (sockaddr*)&addr, sizeof(addr)) == -1)
{
if (ai->ai_family != AF_INET)
continue;
char buffer[NI_MAXHOST];
if (inet_ntop(ai->ai_family, &reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_addr, buffer, sizeof(buffer)) == nullptr)
continue;
printf("%s\n", buffer);
return 0;
perror("connect");
return 1;
}
fprintf(stderr, "no address information available\n");
if (send(socket, argv[1], strlen(argv[1]), 0) == -1)
{
perror("send");
return 1;
}
sockaddr_storage storage;
if (recv(socket, &storage, sizeof(storage), 0) == -1)
{
perror("recv");
return 1;
}
close(socket);
char buffer[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
printf("%s\n", inet_ntop(storage.ss_family, storage.ss_storage, buffer, sizeof(buffer)));
return 0;
}

View File

@ -6,6 +6,4 @@ add_executable(resolver ${SOURCES})
banan_link_library(resolver ban)
banan_link_library(resolver libc)
target_compile_options(resolver PRIVATE -Wno-maybe-uninitialized)
install(TARGETS resolver OPTIONAL)

View File

@ -43,7 +43,6 @@ static_assert(sizeof(DNSAnswer) == 12);
enum QTYPE : uint16_t
{
INVALID = 0x0000,
A = 0x0001,
CNAME = 0x0005,
AAAA = 0x001C,
@ -51,83 +50,14 @@ enum QTYPE : uint16_t
struct DNSEntry
{
DNSEntry(BAN::IPv4Address&& address, time_t valid_until)
: type(QTYPE::A)
, valid_until(valid_until)
, address(BAN::move(address))
{}
DNSEntry(BAN::String&& cname, time_t valid_until)
: type(QTYPE::CNAME)
, valid_until(valid_until)
, cname(BAN::move(cname))
{}
DNSEntry(DNSEntry&& other)
{
*this = BAN::move(other);
}
~DNSEntry() { clear(); }
DNSEntry& operator=(DNSEntry&& other)
{
clear();
valid_until = other.valid_until;
switch (type = other.type)
{
case QTYPE::A:
new (&address) BAN::IPv4Address(BAN::move(other.address));
break;
case QTYPE::CNAME:
new (&cname) BAN::String(BAN::move(other.cname));
break;
case QTYPE::INVALID:
case QTYPE::AAAA:
ASSERT_NOT_REACHED();
}
other.clear();
return *this;
}
void clear()
{
switch (type)
{
case QTYPE::A:
using BAN::IPv4Address;
address.~IPv4Address();
break;
case QTYPE::CNAME:
using BAN::String;
cname.~String();
break;
case QTYPE::AAAA:
ASSERT_NOT_REACHED();
case QTYPE::INVALID:
break;
}
type = QTYPE::INVALID;
}
QTYPE type;
time_t valid_until;
union {
BAN::IPv4Address address;
BAN::String cname;
};
time_t valid_until { 0 };
BAN::IPv4Address address { 0 };
};
struct DNSResponse
{
struct NameEntryPair
{
BAN::String name;
DNSEntry entry;
};
uint16_t id;
BAN::Vector<NameEntryPair> entries;
DNSEntry entry;
};
bool send_dns_query(int socket, BAN::StringView domain, uint16_t id)
@ -180,83 +110,36 @@ BAN::Optional<DNSResponse> read_dns_response(int socket)
}
DNSPacket& reply = *reinterpret_cast<DNSPacket*>(buffer);
DNSResponse result;
result.id = reply.identification;
if (reply.flags & 0x0F)
{
dprintln("DNS error (rcode {})", (unsigned)(reply.flags & 0xF));
return result;
return {};
}
size_t idx = reply.data - buffer;
size_t idx = 0;
for (size_t i = 0; i < reply.question_count; i++)
{
while (buffer[idx])
idx += buffer[idx] + 1;
while (reply.data[idx])
idx += reply.data[idx] + 1;
idx += 5;
}
const auto read_name =
[](size_t idx) -> BAN::String
{
BAN::String result;
while (buffer[idx])
{
if ((buffer[idx] & 0xC0) == 0xC0)
{
idx = ((buffer[idx] & 0x3F) << 8) | buffer[idx + 1];
continue;
}
MUST(result.append(BAN::StringView(reinterpret_cast<const char*>(&buffer[idx + 1]), buffer[idx])));
MUST(result.push_back('.'));
idx += buffer[idx] + 1;
}
if (!result.empty())
result.pop_back();
return result;
};
for (size_t i = 0; i < reply.answer_count; i++)
DNSAnswer& answer = *reinterpret_cast<DNSAnswer*>(&reply.data[idx]);
if (answer.type() != QTYPE::A)
{
auto& answer = *reinterpret_cast<DNSAnswer*>(&buffer[idx]);
auto name = read_name(answer.__storage - buffer);
if (answer.type() == QTYPE::A)
{
if (answer.data_len() != 4)
{
dprintln("Invalid A record size {}", (uint16_t)answer.data_len());
return result;
}
MUST(result.entries.push_back({
.name = BAN::move(name),
.entry = {
BAN::IPv4Address(*reinterpret_cast<uint32_t*>(answer.data)),
time(nullptr) + answer.ttl(),
},
}));
}
else if (answer.type() == QTYPE::CNAME)
{
auto target = read_name(answer.data - buffer);
MUST(result.entries.push_back({
.name = BAN::move(name),
.entry = {
BAN::move(target),
time(nullptr) + answer.ttl()
},
}));
}
idx += sizeof(DNSAnswer) + answer.data_len();
dprintln("Not A record, but {}", static_cast<uint16_t>(answer.type()));
return {};
}
if (answer.data_len() != 4)
{
dprintln("corrupted package");
return {};
}
DNSResponse result;
result.id = reply.identification;
result.entry.valid_until = time(nullptr) + answer.ttl();
result.entry.address = BAN::IPv4Address(*reinterpret_cast<uint32_t*>(answer.data));
return result;
}
@ -310,33 +193,6 @@ BAN::Optional<BAN::String> read_service_query(int socket)
return BAN::String(buffer);
}
BAN::Optional<BAN::IPv4Address> resolve_from_dns_cache(BAN::HashMap<BAN::String, DNSEntry>& dns_cache, const BAN::String& domain)
{
for (auto it = dns_cache.find(domain); it != dns_cache.end();)
{
if (time(nullptr) > it->value.valid_until)
{
dprintln("{} timedout", it->key);
dns_cache.remove(it);
return {};
}
switch (it->value.type)
{
case QTYPE::A:
return it->value.address;
case QTYPE::CNAME:
it = dns_cache.find(it->value.cname);
break;
case QTYPE::AAAA:
case QTYPE::INVALID:
ASSERT_NOT_REACHED();
}
}
return {};
}
int main(int, char**)
{
srand(time(nullptr));
@ -410,42 +266,17 @@ int main(int, char**)
if (!result.has_value())
continue;
for (auto&& [name, entry] : result->entries)
MUST(dns_cache.insert_or_assign(BAN::move(name), BAN::move(entry)));
for (auto& client : clients)
{
if (client.query_id != result->id)
continue;
auto resolved = resolve_from_dns_cache(dns_cache, client.query);
if (!resolved.has_value())
{
auto it = dns_cache.find(client.query);
if (it == dns_cache.end())
{
client.close = true;
break;
}
for (;;)
{
ASSERT(it->value.type == QTYPE::CNAME);
auto next = dns_cache.find(it->value.cname);
if (next == dns_cache.end())
break;
it = next;
}
send_dns_query(service_socket, it->value.cname, client.query_id);
break;
}
(void)dns_cache.insert(client.query, result->entry);
const sockaddr_in addr {
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr = { .s_addr = resolved->raw },
};
if (send(client.socket, &addr, sizeof(addr), 0) == -1)
sockaddr_storage storage;
storage.ss_family = AF_INET;
memcpy(storage.ss_storage, &result->entry.address.raw, sizeof(result->entry.address.raw));
if (send(client.socket, &storage, sizeof(storage), 0) == -1)
dprintln("send: {}", strerror(errno));
client.close = true;
break;
@ -477,22 +308,30 @@ int main(int, char**)
continue;
}
BAN::Optional<BAN::IPv4Address> result;
BAN::Optional<DNSEntry> result;
if (*hostname && strcmp(query->data(), hostname) == 0)
result = BAN::IPv4Address(ntohl(INADDR_LOOPBACK));
else if (auto resolved = resolve_from_dns_cache(dns_cache, query.value()); resolved.has_value())
result = resolved.release_value();
{
result = DNSEntry {
.valid_until = time(nullptr),
.address = ntohl(INADDR_LOOPBACK),
};
}
else if (dns_cache.contains(*query))
{
auto& cached = dns_cache[*query];
if (time(nullptr) <= cached.valid_until)
result = cached;
else
dns_cache.remove(*query);
}
if (result.has_value())
{
const sockaddr_in addr {
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr = { .s_addr = result->raw },
};
if (send(client.socket, &addr, sizeof(addr), 0) == -1)
sockaddr_storage storage;
storage.ss_family = AF_INET;
memcpy(storage.ss_storage, &result->address.raw, sizeof(result->address.raw));
if (send(client.socket, &storage, sizeof(storage), 0) == -1)
dprintln("send: {}", strerror(errno));
client.close = true;
continue;

View File

@ -1,5 +1,4 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
@ -9,26 +8,44 @@
in_addr_t get_ipv4_address(const char* query)
{
const addrinfo hints {
.ai_flags = 0,
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0,
.ai_addrlen = 0,
.ai_addr = nullptr,
.ai_canonname = nullptr,
.ai_next = nullptr,
};
if (in_addr_t ipv4 = inet_addr(query); ipv4 != (in_addr_t)(-1))
return ipv4;
addrinfo* result;
if (getaddrinfo(query, nullptr, &hints, &result) != 0)
int socket = ::socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (socket == -1)
{
perror("socket");
return -1;
}
for (addrinfo* ai = result; ai; ai = ai->ai_next)
if (ai->ai_family != AF_INET)
return reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_addr.s_addr;
sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/resolver.sock");
if (connect(socket, (sockaddr*)&addr, sizeof(addr)) == -1)
{
perror("connect");
close(socket);
return -1;
}
return -1;
if (send(socket, query, strlen(query), 0) == -1)
{
perror("send");
close(socket);
return -1;
}
sockaddr_storage storage;
if (recv(socket, &storage, sizeof(storage), 0) == -1)
{
perror("recv");
close(socket);
return -1;
}
close(socket);
return *reinterpret_cast<in_addr_t*>(storage.ss_storage);
}
int main(int argc, char** argv)