Compare commits

..

55 Commits

Author SHA1 Message Date
d896101268
libos: Remove some shared pointers and change them to owned/live on the stack
Some checks failed
continuous-integration/drone/pr Build is failing
2023-08-14 10:53:21 +02:00
ea25d823e5
wind: Spawn a new client process after startup
Also, create the socket after dropping privileges.
2023-08-14 10:53:21 +02:00
b278ae2dbc
apps: Add gclient 2023-08-14 10:53:21 +02:00
41bf27e510
libos: Add os::LocalClient 2023-08-14 10:53:20 +02:00
935aecb96f
libui: Change 'into' to 'onto' 2023-08-14 10:53:20 +02:00
3025eadc86
libui: Document ui::Font 2023-08-14 10:53:20 +02:00
4bc1530425
libui+wind: Move some static variables inside functions 2023-08-14 10:53:20 +02:00
40b0f8c6ec
wind: Generate random windows on keypresses 2023-08-14 10:53:20 +02:00
47c358555d
wind: Make sure windows have a minimum size to fit the titlebar 2023-08-14 10:53:19 +02:00
a411bb6594
libui: Properly cut off the last drawn character if necessary 2023-08-14 10:53:19 +02:00
2a06a12721
libui: Add Rect::contains(Rect) 2023-08-14 10:53:19 +02:00
cf6fd6ea29
libui: Render font characters properly with no spacing, matching the width calculations 2023-08-14 10:53:19 +02:00
0c2e9551ca
wind: Render an actual TGA mouse cursor 2023-08-14 10:53:19 +02:00
9fd5d0b874
wind: Add a close button to windows using a TGA icon 2023-08-14 10:53:18 +02:00
f8a5f24352
libui: Add support for TGA image loading 2023-08-14 10:53:18 +02:00
dbf014b351
libui: Add an interface to fill a Canvas with an array of pixels 2023-08-14 10:53:18 +02:00
0a630af250
wind: Add window titlebars using ui::Font 2023-08-14 10:53:18 +02:00
dbf9a6bad8
libui: Add PSF font loading and rendering 2023-08-14 10:53:18 +02:00
c3af9091b5
libui: Add Color::GRAY 2023-08-14 10:53:17 +02:00
9fa426eadf
libui: Rename Rect::absolute to normalized and add a new absolute function 2023-08-14 10:53:17 +02:00
7ddac3c36b
libluna: Add assignment operators to Buffer 2023-08-14 10:53:17 +02:00
9aad63474b
wind: Reorder drag sequence 2023-08-14 10:53:17 +02:00
fdc362d19c
libui: Add Rect::relative 2023-08-14 10:53:17 +02:00
6407ec76e0
libui: Remove redundant statement 2023-08-14 10:53:16 +02:00
8e36d25e8a
libui: Add getters for separate color values 2023-08-14 10:53:16 +02:00
a4b6e988b6
libui: Remove unnecessary stuff 2023-08-14 10:53:16 +02:00
442a188630
base: Remove startup items not necessary for GUI startup 2023-08-14 10:53:16 +02:00
871d8cce52
libui+wind: (Draggable) windows 2023-08-14 10:53:15 +02:00
6b32af81f7
wind: Create a local server object 2023-08-14 10:53:15 +02:00
dfe1697ae6
libos: Add a new LocalServer class for local domain sockets 2023-08-14 10:53:15 +02:00
ad0e8bad4a
kernel: Support listening sockets in poll() 2023-08-14 10:53:00 +02:00
987ebe3ef1
base: Start wind on startup instead of the shell 2023-08-14 10:52:59 +02:00
dd9f8afd5b
wind: Add a simple display server skeleton using libui
No client functionality yet, but it's a start.
2023-08-14 10:52:59 +02:00
4b277b38f0
libui: Add a GUI and graphics library 2023-08-14 10:52:59 +02:00
b4ae8bfaa1
kernel: Fix negative movement in the PS/2 mouse driver 2023-08-14 10:52:55 +02:00
ba3e32917e
init: Support starting services as a separate user
Some checks failed
continuous-integration/drone/push Build is failing
2023-08-14 10:46:45 +02:00
cfb60fad25
init: Use pledge and support init --user 2023-08-14 10:46:28 +02:00
9954fc1658
libos: Add a pledge wrapper 2023-08-14 10:45:00 +02:00
a98df9e743
kernel: Return EACCES when trying to apply execpromises to a setuid program
Closes #41.
2023-08-14 09:50:52 +02:00
e2a77bb3da
kernel+libc: Add pledge support
Some checks failed
continuous-integration/drone/push Build is failing
2023-08-12 21:38:25 +02:00
0ae409ae22
ports: Some enhancements in make-package.sh
Some checks failed
continuous-integration/drone/push Build is failing
2023-08-11 18:25:07 +02:00
181b4c151b
tools: Build libstdc++ 2023-08-11 18:24:38 +02:00
0c64b6e040
libc: Add some stub network-related header files 2023-08-11 18:09:45 +02:00
fb3c31907d
fix 2023-08-11 18:09:28 +02:00
52064e0317
libc+kernel: Add alarm() and getpagesize() 2023-08-11 18:09:12 +02:00
ec3c1132d2
libc: Fix constness of some socket functions 2023-08-11 18:00:15 +02:00
5ea73197ad
libluna: Add a bunch more errno definitions 2023-08-11 17:59:41 +02:00
5a1adcb2a6
libc: Add putenv 2023-08-11 17:59:04 +02:00
c4f6191e24
libc: Implement some simple stuff needed for gcc 2023-08-08 22:06:11 +02:00
39e4fbd112
libc: Provide a bunch of math functions wrapped around compiler builtins 2023-08-08 20:38:38 +02:00
32fd6889b9
ports: Add pkg-config wrapper
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-08 20:28:11 +02:00
c6a5a81a7a
ports: Port required libraries to build GCC
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-08 19:51:45 +02:00
3f55a70f6e
ports: Auto-strip binaries, remove libtool .la files, add dependencies 2023-08-08 19:46:04 +02:00
b1e164f360
libc. Add basic wchar.h 2023-08-08 19:43:23 +02:00
ed8b210639
kernel: Detect some other cases of non-DMA support
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-08 18:23:13 +02:00
72 changed files with 1252 additions and 152 deletions

View File

@ -4,9 +4,12 @@
#include <luna/Sort.h> #include <luna/Sort.h>
#include <luna/String.h> #include <luna/String.h>
#include <luna/Vector.h> #include <luna/Vector.h>
#include <os/ArgumentParser.h>
#include <os/Directory.h> #include <os/Directory.h>
#include <os/File.h> #include <os/File.h>
#include <os/Process.h> #include <os/Process.h>
#include <os/Security.h>
#include <pwd.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -17,6 +20,8 @@
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#include <unistd.h> #include <unistd.h>
static bool g_is_system = false;
FILE* g_init_log = nullptr; FILE* g_init_log = nullptr;
// Request a successful exit from the system (for tests) // Request a successful exit from the system (for tests)
@ -40,6 +45,8 @@ struct Service
String standard_output; String standard_output;
String standard_error; String standard_error;
String standard_input; String standard_input;
Option<uid_t> user {};
Option<gid_t> group {};
bool wait { false }; bool wait { false };
Option<pid_t> pid {}; Option<pid_t> pid {};
}; };
@ -65,6 +72,12 @@ static Result<void> service_child(const Service& service, SharedPtr<os::File> ou
if (error) dup2(error->fd(), STDERR_FILENO); if (error) dup2(error->fd(), STDERR_FILENO);
if (input) dup2(input->fd(), STDIN_FILENO); if (input) dup2(input->fd(), STDIN_FILENO);
if (service.user.has_value())
{
setgid(service.group.value());
setuid(service.user.value());
}
if (service.environment.is_empty()) { TRY(os::Process::exec(args[0].view(), args.slice(), false)); } if (service.environment.is_empty()) { TRY(os::Process::exec(args[0].view(), args.slice(), false)); }
else else
{ {
@ -214,6 +227,15 @@ static Result<void> load_service(const os::Path& path)
continue; continue;
} }
if (g_is_system && parts[0].view() == "User")
{
auto* pw = getpwnam(parts[1].chars());
if (!pw) continue;
service.user = pw->pw_uid;
service.group = pw->pw_gid;
continue;
}
if (parts[0].view() == "Wait") if (parts[0].view() == "Wait")
{ {
if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1) if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1)
@ -247,9 +269,9 @@ static Result<void> load_service(const os::Path& path)
return {}; return {};
} }
static Result<void> load_services() static Result<void> load_services(StringView path)
{ {
auto dir = TRY(os::Directory::open("/etc/init")); auto dir = TRY(os::Directory::open(path));
auto services = TRY(dir->list_names(os::Directory::Filter::ParentAndBase)); auto services = TRY(dir->list_names(os::Directory::Filter::ParentAndBase));
sort(services.begin(), services.end(), String::compare); sort(services.begin(), services.end(), String::compare);
@ -259,9 +281,9 @@ static Result<void> load_services()
return {}; return {};
} }
static Result<void> start_services() static Result<void> start_services(StringView path)
{ {
TRY(load_services()); TRY(load_services(path));
for (auto& service : g_services) for (auto& service : g_services)
{ {
do_log("[init] starting service %s\n", service.name.chars()); do_log("[init] starting service %s\n", service.name.chars());
@ -301,7 +323,7 @@ static void mount_shmfs()
if (chmod("/dev/shm", 01777) < 0) exit(255); if (chmod("/dev/shm", 01777) < 0) exit(255);
} }
int main() Result<int> sysinit()
{ {
if (getpid() != 1) if (getpid() != 1)
{ {
@ -309,12 +331,16 @@ int main()
return 1; return 1;
} }
g_is_system = true;
// Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us) // Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us)
// can print stuff. // can print stuff.
stdin = fopen("/dev/console", "r"); stdin = fopen("/dev/console", "r");
stdout = fopen("/dev/console", "w"); stdout = fopen("/dev/console", "w");
stderr = fopen("/dev/console", "w"); stderr = fopen("/dev/console", "w");
TRY(os::Security::pledge("stdio rpath wpath cpath fattr host mount proc exec signal", nullptr));
mount_tmpfs(); mount_tmpfs();
mount_shmfs(); mount_shmfs();
@ -330,7 +356,11 @@ int main()
if (signal(SIGTERM, sigterm_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGTERM\n"); if (signal(SIGTERM, sigterm_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGTERM\n");
if (signal(SIGQUIT, sigquit_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGQUIT\n"); if (signal(SIGQUIT, sigquit_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGQUIT\n");
start_services(); TRY(os::Security::pledge("stdio rpath wpath cpath proc exec", nullptr));
start_services("/etc/init");
TRY(os::Security::pledge("stdio rpath wpath proc exec", nullptr));
while (1) while (1)
{ {
@ -365,3 +395,66 @@ int main()
} }
} }
} }
Result<int> user_init()
{
setpgid(0, 0);
g_init_log = fopen("/dev/uart0", "w");
check(g_init_log);
setlinebuf(g_init_log);
fcntl(fileno(g_init_log), F_SETFD, FD_CLOEXEC);
TRY(os::Security::pledge("stdio rpath wpath cpath proc exec", nullptr));
start_services("/etc/user");
TRY(os::Security::pledge("stdio rpath wpath proc exec", nullptr));
while (1)
{
int status;
auto rc = os::Process::wait(os::Process::ANY_CHILD, &status);
if (rc.has_error()) continue;
pid_t child = rc.release_value();
for (auto& service : g_services)
{
if (service.pid.has_value() && service.pid.value() == child)
{
if (WIFEXITED(status))
{
do_log("[init] service %s exited with status %d\n", service.name.chars(), WEXITSTATUS(status));
}
else
{
do_log("[init] service %s was terminated by signal %d\n", service.name.chars(), WTERMSIG(status));
}
if (service.restart)
{
do_log("[init] restarting service %s\n", service.name.chars());
start_service(service);
}
break;
}
}
}
}
Result<int> luna_main(int argc, char** argv)
{
bool user;
os::ArgumentParser parser;
parser.add_description("The init system for Luna.");
parser.add_system_program_info("init"_sv);
parser.add_switch_argument(user, 'u', "user"_sv, "initialize a user session instead of the system");
parser.parse(argc, argv);
if (user) return user_init();
return sysinit();
}

View File

@ -6,6 +6,8 @@
int main() int main()
{ {
pledge("stdio rpath wpath cpath proc", nullptr);
int fd = shm_open("/shared", O_CREAT | O_RDWR, 0666); int fd = shm_open("/shared", O_CREAT | O_RDWR, 0666);
if (fd < 0) if (fd < 0)
{ {

View File

@ -6,6 +6,7 @@ set(SOURCES
${HEADERS} ${HEADERS}
src/main.cpp src/main.cpp
src/Log.cpp src/Log.cpp
src/Pledge.cpp
src/cxxabi.cpp src/cxxabi.cpp
src/video/Framebuffer.cpp src/video/Framebuffer.cpp
src/video/TextConsole.cpp src/video/TextConsole.cpp
@ -44,6 +45,8 @@ set(SOURCES
src/sys/signal.cpp src/sys/signal.cpp
src/sys/socket.cpp src/sys/socket.cpp
src/sys/poll.cpp src/sys/poll.cpp
src/sys/alarm.cpp
src/sys/pledge.cpp
src/fs/VFS.cpp src/fs/VFS.cpp
src/fs/Pipe.cpp src/fs/Pipe.cpp
src/fs/Mount.cpp src/fs/Mount.cpp

View File

@ -27,8 +27,8 @@ static void log_serial(LogLevel level, const char* format, va_list origin)
va_list ap; va_list ap;
va_copy(ap, origin); va_copy(ap, origin);
const SafeScopeLock lock { g_serial_lock }; /*const SafeScopeLock lock { g_serial_lock };
if (!lock.did_succeed()) return; if (!lock.did_succeed()) return;*/
Serial::printf("\x1b[%sm" Serial::printf("\x1b[%sm"
"%c" "%c"
@ -61,7 +61,7 @@ static void log_text_console(LogLevel level, const char* format, va_list origin)
va_list ap; va_list ap;
va_copy(ap, origin); va_copy(ap, origin);
const ScopeLock lock { g_console_lock }; /*const ScopeLock lock { g_console_lock };*/
const u32 original_foreground = TextConsole::foreground(); const u32 original_foreground = TextConsole::foreground();
const u32 original_background = TextConsole::background(); const u32 original_background = TextConsole::background();

66
kernel/src/Pledge.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "Pledge.h"
#include "Log.h"
#include "memory/MemoryManager.h"
static const char* promise_names[] = {
#define __enumerate(promise) #promise,
enumerate_promises(__enumerate)
#undef __enumerate
};
Result<void> check_pledge(Thread* thread, Promise promise)
{
// Thread has not called pledge().
if (thread->promises < 0) return {};
int mask = (1 << (int)promise);
if ((thread->promises & mask) != mask)
{
kerrorln("Pledge violation in thread %d! Has not pledged %s", thread->id, promise_names[(int)promise]);
if (thread->promises & (1 << (int)Promise::p_error)) return err(ENOSYS);
// Kill this thread with an uncatchable SIGABRT. For this, we reset the disposition of SIGABRT to the default
// (dump core). We could just kill the thread here and be done, but that discards anything on the current stack,
// which means that some destructors might not be called. Instead, leave the job to the next call of
// Thread::process_pending_signals().
thread->signal_handlers[SIGABRT - 1].sa_handler = SIG_DFL;
// If there are any other pending signals, they might be processed before SIGABRT. Avoid that by resetting the
// thread's pending signals.
thread->pending_signals = 0;
thread->send_signal(SIGABRT);
// This should never arrive to userspace.
return err(ENOSYS);
}
return {};
}
Result<int> parse_promises(u64 pledge)
{
if (!pledge) return -1;
auto text = TRY(MemoryManager::strdup_from_user(pledge));
if (text.is_empty()) return 0;
auto promises = TRY(text.split(" "));
int result = 0;
for (const auto& promise : promises)
{
for (int i = 0; i < (int)Promise::num_promises; i++)
{
if (promise.view() == promise_names[i])
{
result |= (1 << i);
goto found;
}
}
return err(EINVAL);
found:
continue;
}
return result;
}

19
kernel/src/Pledge.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "thread/Thread.h"
#include <luna/Result.h>
#define enumerate_promises(_p) \
_p(stdio) _p(rpath) _p(wpath) _p(cpath) _p(fattr) _p(chown) _p(unix) _p(tty) _p(proc) _p(exec) _p(prot_exec) \
_p(id) _p(mount) _p(signal) _p(host) _p(error)
enum class Promise
{
#define __enumerate(promise) p_##promise,
enumerate_promises(__enumerate)
#undef __enumerate
num_promises,
};
Result<void> check_pledge(Thread* thread, Promise promise);
Result<int> parse_promises(u64 pledge);

View File

@ -431,6 +431,18 @@ namespace ATA
m_uses_dma = false; m_uses_dma = false;
} }
if (m_drive_index == 0 && !(status & BMS_MasterInit))
{
kwarnln("ata: Drive %d does not have DMA support", m_drive_index);
m_uses_dma = false;
}
if (m_drive_index == 1 && !(status & BMS_SlaveInit))
{
kwarnln("ata: Drive %d does not have DMA support", m_drive_index);
m_uses_dma = false;
}
auto frame = MemoryManager::alloc_frame(); auto frame = MemoryManager::alloc_frame();
if (frame.has_error() || frame.value() > 0xffffffff) if (frame.has_error() || frame.value() > 0xffffffff)
{ {

View File

@ -1,5 +1,6 @@
#include "fs/devices/ConsoleDevice.h" #include "fs/devices/ConsoleDevice.h"
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "fs/devices/DeviceRegistry.h" #include "fs/devices/DeviceRegistry.h"
#include "fs/devices/KeyboardDevice.h" #include "fs/devices/KeyboardDevice.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
@ -199,6 +200,9 @@ void ConsoleDevice::process_key_event(u8 scancode)
Result<u64> ConsoleDevice::ioctl(int request, void* arg) Result<u64> ConsoleDevice::ioctl(int request, void* arg)
{ {
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_tty));
switch (request) switch (request)
{ {
case TCGETS: { case TCGETS: {

18
kernel/src/sys/alarm.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "Pledge.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
Result<u64> sys_alarm(Registers*, SyscallArgs args)
{
unsigned int seconds = (unsigned int)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
u64 time_left = current->alarm_ticks_left;
current->alarm_ticks_left = seconds * 1000;
return time_left * 1000;
}

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
@ -9,6 +10,8 @@ Result<u64> sys_chdir(Registers*, SyscallArgs args)
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
if (PathParser::is_absolute(path.view())) if (PathParser::is_absolute(path.view()))
{ {
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth)); SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth));

View File

@ -1,6 +1,8 @@
#include "Pledge.h"
#include "arch/Timer.h" #include "arch/Timer.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/clockid.h> #include <bits/clockid.h>
#include <bits/timespec.h> #include <bits/timespec.h>
@ -9,6 +11,10 @@ Result<u64> sys_clock_gettime(Registers*, SyscallArgs args)
clockid_t id = (clockid_t)args[0]; clockid_t id = (clockid_t)args[0];
struct timespec* ts = (struct timespec*)args[1]; struct timespec* ts = (struct timespec*)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
switch (id) switch (id)
{ {
case CLOCK_MONOTONIC: { case CLOCK_MONOTONIC: {

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "binfmt/BinaryFormat.h" #include "binfmt/BinaryFormat.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
@ -63,6 +64,8 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
auto current = Scheduler::current(); auto current = Scheduler::current();
TRY(check_pledge(current, Promise::p_exec));
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory)); auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
if (!VFS::can_execute(inode, current->auth)) return err(EACCES); if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
@ -71,6 +74,11 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
kdbgln("exec: attempting to replace current image with %s", path.chars()); kdbgln("exec: attempting to replace current image with %s", path.chars());
#endif #endif
bool is_setuid = VFS::is_setuid(inode);
bool is_setgid = VFS::is_setgid(inode);
bool is_secure_environment = is_setgid || is_setuid;
if (is_secure_environment && current->execpromises >= 0) return err(EACCES);
auto loader = TRY(BinaryFormat::create_loader(inode)); auto loader = TRY(BinaryFormat::create_loader(inode));
#ifdef EXEC_DEBUG #ifdef EXEC_DEBUG
@ -104,8 +112,8 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
if (descriptor->flags & O_CLOEXEC) { descriptor = {}; } if (descriptor->flags & O_CLOEXEC) { descriptor = {}; }
} }
if (VFS::is_setuid(inode)) current->auth.euid = current->auth.suid = inode->metadata().uid; if (is_setuid) current->auth.euid = current->auth.suid = inode->metadata().uid;
if (VFS::is_setgid(inode)) current->auth.egid = current->auth.sgid = inode->metadata().gid; if (is_setgid) current->auth.egid = current->auth.sgid = inode->metadata().gid;
current->name = path.chars(); current->name = path.chars();
@ -115,6 +123,9 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
current->set_arguments(user_argc, user_argv, user_envc, user_envp); current->set_arguments(user_argc, user_argv, user_envc, user_envp);
current->promises = current->execpromises;
current->execpromises = -1;
memcpy(regs, &current->regs, sizeof(*regs)); memcpy(regs, &current->regs, sizeof(*regs));
for (int i = 0; i < NSIG; i++) for (int i = 0; i < NSIG; i++)
@ -133,6 +144,8 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
{ {
auto current = Scheduler::current(); auto current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); }); auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
memcpy(&current->regs, regs, sizeof(*regs)); memcpy(&current->regs, regs, sizeof(*regs));
@ -152,6 +165,8 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
thread->current_directory_path = move(current_directory_path); thread->current_directory_path = move(current_directory_path);
thread->umask = current->umask; thread->umask = current->umask;
thread->parent = current; thread->parent = current;
thread->promises = current->promises;
thread->execpromises = current->execpromises;
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; } for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }
@ -159,11 +174,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
memcpy(&thread->regs, regs, sizeof(*regs)); memcpy(&thread->regs, regs, sizeof(*regs));
for (int i = 0; i < NSIG; i++) for (int i = 0; i < NSIG; i++) thread->signal_handlers[i] = current->signal_handlers[i];
{
auto sighandler = current->signal_handlers[i].sa_handler;
thread->signal_handlers[i] = { .sa_handler = sighandler, .sa_mask = 0, .sa_flags = 0 };
}
thread->signal_mask = current->signal_mask; thread->signal_mask = current->signal_mask;
thread->set_return(0); thread->set_return(0);

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "fs/Pipe.h" #include "fs/Pipe.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
@ -24,6 +25,8 @@ Result<u64> sys_read(Registers* regs, SyscallArgs args)
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd)); auto& descriptor = *TRY(current->resolve_fd(fd));
if (!descriptor.is_readable()) return err(EBADF); if (!descriptor.is_readable()) return err(EBADF);
@ -65,6 +68,8 @@ Result<u64> sys_write(Registers*, SyscallArgs args)
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd)); auto& descriptor = *TRY(current->resolve_fd(fd));
if (!descriptor.is_writable()) return err(EBADF); if (!descriptor.is_writable()) return err(EBADF);
@ -87,6 +92,8 @@ Result<u64> sys_lseek(Registers*, SyscallArgs args)
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd)); auto& descriptor = *TRY(current->resolve_fd(fd));
if (descriptor.inode()->type() == VFS::InodeType::FIFO) return err(ESPIPE); if (descriptor.inode()->type() == VFS::InodeType::FIFO) return err(ESPIPE);
@ -117,6 +124,8 @@ Result<u64> sys_fcntl(Registers*, SyscallArgs args)
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd)); auto& descriptor = *TRY(current->resolve_fd(fd));
bool is_cloexec = true; bool is_cloexec = true;
@ -176,6 +185,7 @@ Result<u64> sys_isatty(Registers*, SyscallArgs args)
int fd = (int)args[0]; int fd = (int)args[0];
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd)); auto& descriptor = *TRY(current->resolve_fd(fd));
return descriptor.inode()->isatty(); return descriptor.inode()->isatty();
@ -188,6 +198,8 @@ Result<u64> sys_dup2(Registers*, SyscallArgs args)
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
if (newfd < 0 || newfd >= FD_MAX) return err(EBADF); if (newfd < 0 || newfd >= FD_MAX) return err(EBADF);
auto descriptor = *TRY(current->resolve_fd(oldfd)); auto descriptor = *TRY(current->resolve_fd(oldfd));
@ -206,6 +218,8 @@ Result<u64> sys_pipe(Registers*, SyscallArgs args)
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
int rfd = TRY(current->allocate_fd(0)); int rfd = TRY(current->allocate_fd(0));
int wfd = TRY(current->allocate_fd(rfd + 1)); int wfd = TRY(current->allocate_fd(rfd + 1));
@ -229,6 +243,8 @@ Result<u64> sys_umask(Registers*, SyscallArgs args)
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
mode_t old_umask = current->umask; mode_t old_umask = current->umask;
current->umask = new_umask & 0777; current->umask = new_umask & 0777;
@ -242,6 +258,7 @@ Result<u64> sys_truncate(Registers*, SyscallArgs args)
size_t length = (size_t)args[1]; size_t length = (size_t)args[1];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_wpath));
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory)); auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
if (!VFS::can_write(inode, current->auth)) return err(EACCES); if (!VFS::can_write(inode, current->auth)) return err(EACCES);
@ -257,6 +274,7 @@ Result<u64> sys_ftruncate(Registers*, SyscallArgs args)
size_t length = (size_t)args[1]; size_t length = (size_t)args[1];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto description = TRY(current->resolve_fd(fd))->description; auto description = TRY(current->resolve_fd(fd))->description;
if (!(description->flags & O_WRONLY)) return err(EBADF); if (!(description->flags & O_WRONLY)) return err(EBADF);
@ -273,6 +291,7 @@ Result<u64> sys_utimensat(Registers*, SyscallArgs args)
int flags = (int)args[3]; int flags = (int)args[3];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_fattr));
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW))); auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
struct timespec ktimes[2]; struct timespec ktimes[2];

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
@ -11,6 +12,7 @@ Result<u64> sys_getdents(Registers*, SyscallArgs args)
usize count = (usize)args[2]; usize count = (usize)args[2];
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd)); auto& descriptor = *TRY(current->resolve_fd(fd));

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
@ -5,41 +6,54 @@
Result<u64> sys_getpid(Registers*, SyscallArgs) Result<u64> sys_getpid(Registers*, SyscallArgs)
{ {
return Scheduler::current()->id; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->id;
} }
Result<u64> sys_getppid(Registers*, SyscallArgs) Result<u64> sys_getppid(Registers*, SyscallArgs)
{ {
auto* parent = Scheduler::current()->parent; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto* parent = current->parent;
return parent ? parent->id : 0; return parent ? parent->id : 0;
} }
Result<u64> sys_getuid(Registers*, SyscallArgs) Result<u64> sys_getuid(Registers*, SyscallArgs)
{ {
return Scheduler::current()->auth.uid; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.uid;
} }
Result<u64> sys_geteuid(Registers*, SyscallArgs) Result<u64> sys_geteuid(Registers*, SyscallArgs)
{ {
return Scheduler::current()->auth.euid; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.euid;
} }
Result<u64> sys_getgid(Registers*, SyscallArgs) Result<u64> sys_getgid(Registers*, SyscallArgs)
{ {
return Scheduler::current()->auth.gid; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.gid;
} }
Result<u64> sys_getegid(Registers*, SyscallArgs) Result<u64> sys_getegid(Registers*, SyscallArgs)
{ {
return Scheduler::current()->auth.egid; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.egid;
} }
Result<u64> sys_setuid(Registers*, SyscallArgs args) Result<u64> sys_setuid(Registers*, SyscallArgs args)
{ {
u32 uid = (u32)args[0]; u32 uid = (u32)args[0];
Credentials& auth = Scheduler::current()->auth; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid == 0) if (auth.euid == 0)
{ {
@ -57,7 +71,9 @@ Result<u64> sys_seteuid(Registers*, SyscallArgs args)
{ {
u32 uid = (u32)args[0]; u32 uid = (u32)args[0];
Credentials& auth = Scheduler::current()->auth; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid != 0 && uid != auth.uid && uid != auth.suid) return err(EPERM); if (auth.euid != 0 && uid != auth.uid && uid != auth.suid) return err(EPERM);
auth.euid = uid; auth.euid = uid;
@ -69,7 +85,9 @@ Result<u64> sys_setgid(Registers*, SyscallArgs args)
{ {
u32 gid = (u32)args[0]; u32 gid = (u32)args[0];
Credentials& auth = Scheduler::current()->auth; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid == 0) if (auth.euid == 0)
{ {
@ -87,7 +105,9 @@ Result<u64> sys_setegid(Registers*, SyscallArgs args)
{ {
u32 gid = (u32)args[0]; u32 gid = (u32)args[0];
Credentials& auth = Scheduler::current()->auth; auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid != 0 && gid != auth.gid && gid != auth.sgid) return err(EPERM); if (auth.euid != 0 && gid != auth.gid && gid != auth.sgid) return err(EPERM);
auth.egid = gid; auth.egid = gid;
@ -101,6 +121,7 @@ Result<u64> sys_setpgid(Registers*, SyscallArgs args)
pid_t pgid = (pid_t)args[1]; pid_t pgid = (pid_t)args[1];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
if (pid == 0) pid = current->id; if (pid == 0) pid = current->id;
if (pgid == 0) pgid = current->id; if (pgid == 0) pgid = current->id;
@ -133,6 +154,7 @@ Result<u64> sys_getpgid(Registers*, SyscallArgs args)
pid_t pid = (pid_t)args[0]; pid_t pid = (pid_t)args[0];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
if (pid == 0) pid = current->id; if (pid == 0) pid = current->id;
if (pid < 0) return err(EINVAL); if (pid < 0) return err(EINVAL);
@ -150,6 +172,7 @@ Result<u64> sys_fchmodat(Registers*, SyscallArgs args)
int flags = (int)args[3]; int flags = (int)args[3];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_wpath));
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW))); auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
@ -171,6 +194,7 @@ Result<u64> sys_fchownat(Registers*, SyscallArgs args)
int flags = (int)args[4]; int flags = (int)args[4];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_chown));
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW))); auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
@ -12,6 +13,7 @@ Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
int flags = (int)args[2]; int flags = (int)args[2];
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto dirname = TRY(PathParser::dirname(path.view())); auto dirname = TRY(PathParser::dirname(path.view()));
auto basename = TRY(PathParser::basename(path.view())); auto basename = TRY(PathParser::basename(path.view()));
@ -44,6 +46,7 @@ Result<u64> sys_symlinkat(Registers*, SyscallArgs args)
if (target.is_empty()) return err(ENOENT); if (target.is_empty()) return err(ENOENT);
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto parent = TRY(PathParser::dirname(linkpath.view())); auto parent = TRY(PathParser::dirname(linkpath.view()));
@ -73,6 +76,7 @@ Result<u64> sys_readlinkat(Registers*, SyscallArgs args)
usize bufsiz = (usize)args[3]; usize bufsiz = (usize)args[3];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
auto symlink = TRY(current->resolve_atfile(dirfd, path, true, false)); auto symlink = TRY(current->resolve_atfile(dirfd, path, true, false));
@ -98,6 +102,7 @@ Result<u64> sys_linkat(Registers*, SyscallArgs args)
int flags = (int)args[4]; int flags = (int)args[4];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto parent = TRY(PathParser::dirname(newpath.view())); auto parent = TRY(PathParser::dirname(newpath.view()));

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
@ -10,6 +11,7 @@ Result<u64> sys_mkdir(Registers*, SyscallArgs args)
mode_t mode = (mode_t)args[1]; mode_t mode = (mode_t)args[1];
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto inode = auto inode =
TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, current->current_directory)); TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, current->current_directory));

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "arch/MMU.h" #include "arch/MMU.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "memory/SharedMemory.h" #include "memory/SharedMemory.h"
@ -22,6 +23,8 @@ Result<u64> sys_mmap(Registers*, SyscallArgs args)
if (params.flags < 0) return err(EINVAL); if (params.flags < 0) return err(EINVAL);
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
if (params.prot & PROT_EXEC) TRY(check_pledge(current, Promise::p_prot_exec));
TRY(check_pledge(current, Promise::p_stdio));
SharedPtr<OpenFileDescription> description; SharedPtr<OpenFileDescription> description;
if ((params.flags & MAP_ANONYMOUS) != MAP_ANONYMOUS) if ((params.flags & MAP_ANONYMOUS) != MAP_ANONYMOUS)
@ -94,6 +97,7 @@ Result<u64> sys_munmap(Registers*, SyscallArgs args)
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL); if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
bool ok = TRY(current->address_space->free_region(address, ceil_div(size, ARCH_PAGE_SIZE))); bool ok = TRY(current->address_space->free_region(address, ceil_div(size, ARCH_PAGE_SIZE)));
@ -118,6 +122,7 @@ Result<u64> sys_msync(Registers*, SyscallArgs args)
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL); if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
TRY(current->address_space->sync_regions(address, ceil_div(size, ARCH_PAGE_SIZE))); TRY(current->address_space->sync_regions(address, ceil_div(size, ARCH_PAGE_SIZE)));

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "fs/ext2/FileSystem.h" #include "fs/ext2/FileSystem.h"
#include "fs/tmpfs/FileSystem.h" #include "fs/tmpfs/FileSystem.h"
@ -12,6 +13,7 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
auto source = TRY(MemoryManager::strdup_from_user(args[2])); auto source = TRY(MemoryManager::strdup_from_user(args[2]));
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_mount));
if (current->auth.euid != 0) return err(EPERM); if (current->auth.euid != 0) return err(EPERM);
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> { auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
@ -44,6 +46,7 @@ Result<u64> sys_umount(Registers*, SyscallArgs args)
auto target = TRY(MemoryManager::strdup_from_user(args[0])); auto target = TRY(MemoryManager::strdup_from_user(args[0]));
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_mount));
if (current->auth.euid != 0) return err(EPERM); if (current->auth.euid != 0) return err(EPERM);
TRY(VFS::umount(target.chars(), current->auth, current->current_directory)); TRY(VFS::umount(target.chars(), current->auth, current->current_directory));
@ -57,6 +60,7 @@ Result<u64> sys_pivot_root(Registers*, SyscallArgs args)
auto put_old = TRY(MemoryManager::strdup_from_user(args[1])); auto put_old = TRY(MemoryManager::strdup_from_user(args[1]));
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_mount));
if (current->auth.euid != 0) return err(EPERM); if (current->auth.euid != 0) return err(EPERM);
TRY(VFS::pivot_root(new_root.chars(), put_old.chars(), current->current_directory)); TRY(VFS::pivot_root(new_root.chars(), put_old.chars(), current->current_directory));

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
@ -23,6 +24,12 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
// Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR // Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR
if ((flags & O_RDWR) == 0) { return err(EINVAL); } if ((flags & O_RDWR) == 0) { return err(EINVAL); }
if (flags & O_RDONLY) TRY(check_pledge(current, Promise::p_rpath));
else if (flags & O_WRONLY)
TRY(check_pledge(current, Promise::p_wpath));
if (flags & O_CREAT) TRY(check_pledge(current, Promise::p_cpath));
if (flags & O_TMPFILE) if (flags & O_TMPFILE)
{ {
if (!(flags & O_WRONLY)) return err(EINVAL); if (!(flags & O_WRONLY)) return err(EINVAL);
@ -99,6 +106,7 @@ Result<u64> sys_close(Registers*, SyscallArgs args)
if (fd < 0 || fd >= FD_MAX) return err(EBADF); if (fd < 0 || fd >= FD_MAX) return err(EBADF);
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
Option<FileDescriptor>& descriptor = current->fd_table[fd]; Option<FileDescriptor>& descriptor = current->fd_table[fd];

40
kernel/src/sys/pledge.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "Pledge.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
Result<u64> sys_pledge(Registers*, SyscallArgs args)
{
int promises = TRY(parse_promises(args[0]));
int execpromises = TRY(parse_promises(args[1]));
auto* current = Scheduler::current();
if (promises >= 0)
{
int actual_promises = promises & ~(1 << (int)Promise::p_error);
int old_promises = current->promises & ~(1 << (int)Promise::p_error);
if (actual_promises & ~old_promises)
{
if (current->promises & ~(1 << (int)Promise::p_error)) return 0;
return err(EPERM);
}
}
if (execpromises >= 0)
{
int actual_execpromises = execpromises & ~(1 << (int)Promise::p_error);
int old_execpromises = current->execpromises & ~(1 << (int)Promise::p_error);
if (actual_execpromises & ~old_execpromises)
{
if (current->execpromises & ~(1 << (int)Promise::p_error)) return 0;
return err(EPERM);
}
}
if (promises >= 0) current->promises = promises;
if (execpromises >= 0) current->execpromises = execpromises;
return 0;
}

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "net/Socket.h" #include "net/Socket.h"
@ -19,6 +20,7 @@ Result<u64> sys_poll(Registers*, SyscallArgs args)
Vector<SharedPtr<VFS::Inode>> inodes; Vector<SharedPtr<VFS::Inode>> inodes;
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
for (nfds_t i = 0; i < nfds; i++) for (nfds_t i = 0; i < nfds; i++)
{ {

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
@ -14,6 +15,9 @@ Result<u64> sys_pstat(Registers*, SyscallArgs args)
pid_t pid = (pid_t)args[0]; pid_t pid = (pid_t)args[0];
struct process* ps = (struct process*)args[1]; struct process* ps = (struct process*)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
// If pid == -1, return the PID of the last spawned thread. // If pid == -1, return the PID of the last spawned thread.
if (pid == -1) return g_threads.expect_last()->id; if (pid == -1) return g_threads.expect_last()->id;

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
@ -18,6 +19,7 @@ Result<u64> sys_sigreturn(Registers* regs, SyscallArgs)
Result<u64> sys_sigaction(Registers*, SyscallArgs args) Result<u64> sys_sigaction(Registers*, SyscallArgs args)
{ {
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_signal));
int signo = (int)args[0]; int signo = (int)args[0];
const struct sigaction* act = (const struct sigaction*)args[1]; const struct sigaction* act = (const struct sigaction*)args[1];
@ -47,6 +49,7 @@ Result<u64> sys_sigaction(Registers*, SyscallArgs args)
Result<u64> sys_kill(Registers*, SyscallArgs args) Result<u64> sys_kill(Registers*, SyscallArgs args)
{ {
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
pid_t pid = (pid_t)args[0]; pid_t pid = (pid_t)args[0];
int signo = (int)args[1]; int signo = (int)args[1];
@ -68,6 +71,7 @@ Result<u64> sys_kill(Registers*, SyscallArgs args)
Result<u64> sys_sigprocmask(Registers*, SyscallArgs args) Result<u64> sys_sigprocmask(Registers*, SyscallArgs args)
{ {
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_signal));
int how = (int)args[0]; int how = (int)args[0];
const sigset_t* set = (const sigset_t*)args[1]; const sigset_t* set = (const sigset_t*)args[1];

View File

@ -1,4 +1,5 @@
#include "net/Socket.h" #include "net/Socket.h"
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "net/UnixSocket.h" #include "net/UnixSocket.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
@ -14,9 +15,10 @@ Result<u64> sys_socket(Registers*, SyscallArgs args)
if (type != SOCK_STREAM) return err(EPROTOTYPE); if (type != SOCK_STREAM) return err(EPROTOTYPE);
if (domain != AF_UNIX) return err(EAFNOSUPPORT); if (domain != AF_UNIX) return err(EAFNOSUPPORT);
auto socket = TRY(make_shared<UnixSocket>());
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto socket = TRY(make_shared<UnixSocket>());
int fd = TRY(current->allocate_fd(0)); int fd = TRY(current->allocate_fd(0));
@ -36,6 +38,7 @@ Result<u64> sys_bind(Registers*, SyscallArgs args)
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT); if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto inode = TRY(current->resolve_fd(sockfd))->inode(); auto inode = TRY(current->resolve_fd(sockfd))->inode();
@ -59,6 +62,7 @@ Result<u64> sys_connect(Registers* regs, SyscallArgs args)
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT); if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto description = TRY(current->resolve_fd(sockfd))->description; auto description = TRY(current->resolve_fd(sockfd))->description;
@ -77,6 +81,7 @@ Result<u64> sys_listen(Registers*, SyscallArgs args)
int backlog = (int)args[1]; int backlog = (int)args[1];
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto inode = TRY(current->resolve_fd(sockfd))->inode(); auto inode = TRY(current->resolve_fd(sockfd))->inode();
@ -104,6 +109,7 @@ Result<u64> sys_accept(Registers* regs, SyscallArgs args)
} }
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto description = TRY(current->resolve_fd(sockfd))->description; auto description = TRY(current->resolve_fd(sockfd))->description;

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
@ -33,6 +34,7 @@ Result<u64> sys_fstatat(Registers*, SyscallArgs args)
int flags = (int)args[3]; int flags = (int)args[3];
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW))); auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
@ -67,6 +69,7 @@ Result<u64> sys_faccessat(Registers*, SyscallArgs args)
Credentials creds; Credentials creds;
auto* current = Scheduler::current(); auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
if (flags & AT_EACCESS) creds = current->auth; if (flags & AT_EACCESS) creds = current->auth;
else else

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "arch/CPU.h" #include "arch/CPU.h"
#include "config.h" #include "config.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
@ -40,6 +41,7 @@ Result<u64> sys_sethostname(Registers*, SyscallArgs args)
usize length = (usize)args[1]; usize length = (usize)args[1];
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_host));
if (current->auth.euid != 0) return err(EPERM); if (current->auth.euid != 0) return err(EPERM);
if (length >= _UTSNAME_LENGTH) return err(EINVAL); if (length >= _UTSNAME_LENGTH) return err(EINVAL);

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
#include <sys/types.h> #include <sys/types.h>
@ -6,12 +7,13 @@ Result<u64> sys_usleep(Registers*, SyscallArgs args)
{ {
useconds_t us = (useconds_t)args[0]; useconds_t us = (useconds_t)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
// FIXME: Allow usleep() to use a more precise resolution. // FIXME: Allow usleep() to use a more precise resolution.
if (us < 1000) return 0; if (us < 1000) return 0;
kernel_sleep(us / 1000); kernel_sleep(us / 1000);
auto* current = Scheduler::current();
return current->sleep_ticks_left; return current->sleep_ticks_left;
} }

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "Pledge.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
@ -11,6 +12,7 @@ Result<u64> sys_waitpid(Registers* regs, SyscallArgs args)
int options = (int)args[2]; int options = (int)args[2];
Thread* current = Scheduler::current(); Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
Thread* thread; Thread* thread;

View File

@ -282,6 +282,8 @@ namespace Scheduler
{ {
if (thread->sleep_ticks_left == 0 || --thread->sleep_ticks_left == 0) thread->wake_up(); if (thread->sleep_ticks_left == 0 || --thread->sleep_ticks_left == 0) thread->wake_up();
} }
if (thread->alarm_ticks_left && --thread->alarm_ticks_left == 0) thread->send_signal(SIGALRM);
} }
if (!g_current->ticks_left) switch_task(regs); if (!g_current->ticks_left) switch_task(regs);

View File

@ -87,6 +87,10 @@ struct Thread : public LinkedListNode<Thread>
u64 ticks_left; u64 ticks_left;
u64 sleep_ticks_left; u64 sleep_ticks_left;
u64 alarm_ticks_left { 0 };
int promises { -1 };
int execpromises { -1 };
Stack stack; Stack stack;
Stack kernel_stack; Stack kernel_stack;

View File

@ -25,6 +25,7 @@ set(SOURCES
src/termios.cpp src/termios.cpp
src/utime.cpp src/utime.cpp
src/strtod.cpp src/strtod.cpp
src/math.cpp
src/sys/stat.cpp src/sys/stat.cpp
src/sys/mman.cpp src/sys/mman.cpp
src/sys/wait.cpp src/sys/wait.cpp

0
libc/include/arpa/inet.h Normal file
View File

View File

@ -5,6 +5,28 @@
#include <bits/locale-cat.h> #include <bits/locale-cat.h>
struct lconv
{
char* decimal_point;
char* thousands_sep;
char* grouping;
char* int_curr_symbol;
char* currency_symbol;
char* mon_decimal_point;
char* mon_thousands_sep;
char* mon_grouping;
char* positive_sign;
char* negative_sign;
char int_frac_digits;
char frac_digits;
char p_cs_precedes;
char p_sep_by_space;
char n_cs_precedes;
char n_sep_by_space;
char p_sign_posn;
char n_sign_posn;
};
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
@ -13,6 +35,9 @@ extern "C"
// Query or set the current locale. // Query or set the current locale.
char* setlocale(int category, const char* locale); char* setlocale(int category, const char* locale);
// Query formatting information for the current locale.
struct lconv* localeconv(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -0,0 +1,92 @@
/* math.h: Floating-point arithmetic functions. */
#ifndef _MATH_H
#define _MATH_H
typedef float float_t;
typedef double double_t;
#define FP_NAN 0
#define FP_INFINITE 1
#define FP_ZERO 2
#define FP_SUBNORMAL 3
#define FP_NORMAL 4
#define fpclassify(x) __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_ZERO, x)
#ifdef __cplusplus
extern "C"
{
#endif
double cos(double val);
float cosf(float val);
long double cosl(long double val);
double sin(double val);
float sinf(float val);
long double sinl(long double val);
double tan(double val);
float tanf(float val);
long double tanl(long double val);
double acos(double val);
float acosf(float val);
long double acosl(long double val);
double asin(double val);
float asinf(float val);
long double asinl(long double val);
double atan(double val);
float atanf(float val);
long double atanl(long double val);
double cosh(double val);
float coshf(float val);
long double coshl(long double val);
double sinh(double val);
float sinhf(float val);
long double sinhl(long double val);
double tanh(double val);
float tanhf(float val);
long double tanhl(long double val);
double log(double val);
float logf(float val);
long double logl(long double val);
double exp(double val);
float expf(float val);
long double expl(long double val);
double sqrt(double val);
float sqrtf(float val);
long double sqrtl(long double val);
double fabs(double val);
float fabsf(float val);
long double fabsl(long double val);
double floor(double val);
float floorf(float val);
long double floorl(long double val);
double ceil(double val);
float ceilf(float val);
long double ceill(long double val);
double log10(double val);
float log10f(float val);
long double log10l(long double val);
double fmod(double val1, double val2);
float fmodf(float val1, float val2);
long double fmodl(long double val1, long double val2);
double pow(double val1, double val2);
float powf(float val1, float val2);
long double powl(long double val1, long double val2);
double atan2(double val1, double val2);
float atan2f(float val1, float val2);
long double atan2l(long double val1, long double val2);
double frexp(double val1, int* val2);
float frexpf(float val1, int* val2);
long double frexpl(long double val1, int* val2);
double ldexp(double val1, int val2);
float ldexpf(float val1, int val2);
long double ldexpl(long double val1, int val2);
double modf(double val1, double* val2);
float modff(float val1, float* val2);
long double modfl(long double val1, long double* val2);
#ifdef __cplusplus
}
#endif
#endif

0
libc/include/netdb.h Normal file
View File

View File

View File

@ -198,6 +198,9 @@ extern "C"
/* Change a file's buffering mode to line buffered. */ /* Change a file's buffering mode to line buffered. */
void setlinebuf(FILE* stream); void setlinebuf(FILE* stream);
/* Move a file's location across a file system. */
int rename(const char* oldpath, const char* newpath);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -128,6 +128,9 @@ extern "C"
/* Clear all environment variables. */ /* Clear all environment variables. */
int clearenv(void); int clearenv(void);
/* Add a new variable to the environment. */
int putenv(char* string);
/* Sort an array of arbitrary elements using a comparison function. */ /* Sort an array of arbitrary elements using a comparison function. */
void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));

View File

@ -98,6 +98,9 @@ extern "C"
/* Compare two null-terminated strings according to the current locale. */ /* Compare two null-terminated strings according to the current locale. */
int strcoll(const char* a, const char* b); int strcoll(const char* a, const char* b);
/* Transform a string according to the current locale. */
size_t strxfrm(char* dest, const char* src, size_t n);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -14,10 +14,10 @@ extern "C"
int socket(int domain, int type, int protocol); int socket(int domain, int type, int protocol);
/* Bind a socket to an address. */ /* Bind a socket to an address. */
int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen); int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
/* Connect a socket to a remote address. */ /* Connect a socket to a remote address. */
int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen); int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
/* Start listening on a socket. */ /* Start listening on a socket. */
int listen(int sockfd, int backlog); int listen(int sockfd, int backlog);

View File

@ -7,6 +7,10 @@
#include <bits/struct_tm.h> #include <bits/struct_tm.h>
#include <bits/timespec.h> #include <bits/timespec.h>
typedef long int clock_t;
#define CLOCKS_PER_SEC 1000000
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
@ -42,9 +46,18 @@ extern "C"
/* Build a string representation of UNIX time. */ /* Build a string representation of UNIX time. */
char* ctime_r(const time_t* tp, char buf[26]); char* ctime_r(const time_t* tp, char buf[26]);
/* Convert broken-down time back into UNIX time. */
time_t mktime(struct tm* tm);
/* Format a string representation of broken-down time using a format string. */ /* Format a string representation of broken-down time using a format string. */
size_t strftime(char* buf, size_t max, const char* format, const struct tm* tm); size_t strftime(char* buf, size_t max, const char* format, const struct tm* tm);
/* Return the difference in seconds between two times. */
double difftime(time_t a, time_t b);
/* Estimate the CPU time used by a process. */
clock_t clock(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -190,6 +190,15 @@ extern "C"
/* Truncate a file to a specific length. */ /* Truncate a file to a specific length. */
int ftruncate(int fd, size_t size); int ftruncate(int fd, size_t size);
/* Return the system page size. */
int getpagesize(void);
/* Schedule an alarm signal. */
unsigned int alarm(unsigned int seconds);
/* Restrict system operations. */
int pledge(const char* promises, const char* execpromises);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -0,0 +1,25 @@
/* wchar.h: Wide-character string manipulation functions. */
#ifndef _WCHAR_H
#define _WCHAR_H
typedef long int wint_t;
#include <stddef.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Calculate the size of a null-terminated wide character string. */
size_t wcslen(const wchar_t* str);
/* Compare two null-terminated wide character strings. */
int wcscmp(const wchar_t* a, const wchar_t* b);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,11 +1,13 @@
#include <bits/errno-return.h> #include <bits/errno-return.h>
#include <errno.h> #include <errno.h>
#include <luna/HashTable.h>
#include <luna/ScopeGuard.h> #include <luna/ScopeGuard.h>
#include <luna/Vector.h> #include <luna/Vector.h>
#include <stdlib.h> #include <stdlib.h>
extern "C" char** environ; extern "C" char** environ;
Vector<char*> g_dynamic_env = {}; Vector<char*> g_dynamic_env = {};
HashTable<char*> g_dynamic_vars = {};
bool env_is_dynamic { false }; bool env_is_dynamic { false };
/* If an environment variable matching key is found, stores its value in value and returns its index. Otherwise, /* If an environment variable matching key is found, stores its value in value and returns its index. Otherwise,
@ -41,22 +43,24 @@ static isize _findenv(const char* key, char** value)
return -1; return -1;
} }
static void free_if_needed(char* element)
{
if (g_dynamic_vars.try_find(element))
{
g_dynamic_vars.try_remove(element);
free(element);
}
}
/* Move environ to a heap-allocated array. */ /* Move environ to a heap-allocated array. */
static Result<void> _try_move_env() static Result<void> _try_move_env()
{ {
char** env = environ; char** env = environ;
g_dynamic_env.clear(); g_dynamic_env.clear();
auto guard = make_scope_guard([] {
for (auto element : g_dynamic_env)
{
if (element) free(element);
}
});
if (!env) if (!env)
{ {
TRY(g_dynamic_env.try_append(nullptr)); TRY(g_dynamic_env.try_append(nullptr));
guard.deactivate();
env_is_dynamic = true; env_is_dynamic = true;
environ = g_dynamic_env.data(); environ = g_dynamic_env.data();
return {}; return {};
@ -64,18 +68,12 @@ static Result<void> _try_move_env()
while (*env) while (*env)
{ {
char* ptr = strdup(*(env++)); char* ptr = *(env++);
if (!ptr) return err(errno);
auto ptr_guard = make_scope_guard([=] { free(ptr); });
TRY(g_dynamic_env.try_append(ptr)); TRY(g_dynamic_env.try_append(ptr));
ptr_guard.deactivate();
} }
TRY(g_dynamic_env.try_append(nullptr)); TRY(g_dynamic_env.try_append(nullptr));
guard.deactivate();
env_is_dynamic = true; env_is_dynamic = true;
environ = g_dynamic_env.data(); environ = g_dynamic_env.data();
@ -105,7 +103,7 @@ static void _check_dynamic_env()
{ {
for (auto element : g_dynamic_env) for (auto element : g_dynamic_env)
{ {
if (element) free(element); if (element) free_if_needed(element);
} }
} }
} }
@ -122,7 +120,7 @@ extern "C"
{ {
for (auto element : g_dynamic_env) for (auto element : g_dynamic_env)
{ {
if (element) free(element); if (element) free_if_needed(element);
} }
g_dynamic_env.clear(); g_dynamic_env.clear();
@ -152,9 +150,11 @@ extern "C"
if (_move_env() < 0) return -1; if (_move_env() < 0) return -1;
} }
g_dynamic_env.remove_at(index); char* p = g_dynamic_env.remove_at(index);
_update_env(); _update_env();
free_if_needed(p);
return 0; return 0;
} }
@ -188,12 +188,14 @@ extern "C"
if (index >= 0) if (index >= 0)
{ {
free(environ[index]); free_if_needed(environ[index]);
environ[index] = str; environ[index] = str;
guard.deactivate(); guard.deactivate();
return 0; return 0;
} }
TRY_OR_SET_ERRNO(g_dynamic_vars.try_set(str), int, -1);
// Add a new NULL at the end of the array and replace the previous one with our string. // Add a new NULL at the end of the array and replace the previous one with our string.
index = g_dynamic_env.size() - 1; index = g_dynamic_env.size() - 1;
@ -206,6 +208,43 @@ extern "C"
return 0; return 0;
} }
int putenv(char* string)
{
char* p = strchr(string, '=');
if (!p) return unsetenv(string);
size_t key_len = p - string;
char* key = strndup(string, key_len);
auto guard = make_scope_guard([key] { free(key); });
auto index = _findenv(key, nullptr);
_check_dynamic_env();
if (!env_is_dynamic)
{
if (_move_env() < 0) return -1;
}
if (index >= 0)
{
free_if_needed(environ[index]);
environ[index] = string;
return 0;
}
// Add a new NULL at the end of the array and replace the previous one with our string.
index = g_dynamic_env.size() - 1;
TRY_OR_SET_ERRNO(g_dynamic_env.try_append(nullptr), int, -1);
guard.deactivate();
_update_env();
environ[index] = string;
return 0;
}
char* getenv(const char* key) char* getenv(const char* key)
{ {
char* result; char* result;

View File

@ -1,6 +1,30 @@
#include <limits.h>
#include <locale.h> #include <locale.h>
static char s_default_locale[] = "C"; static char s_default_locale[] = "C";
static char s_empty_string[] = "";
static char s_decimal_point[] = ".";
static struct lconv s_lconv = {
.decimal_point = s_decimal_point,
.thousands_sep = s_empty_string,
.grouping = s_empty_string,
.int_curr_symbol = s_empty_string,
.currency_symbol = s_empty_string,
.mon_decimal_point = s_empty_string,
.mon_thousands_sep = s_empty_string,
.mon_grouping = s_empty_string,
.positive_sign = s_empty_string,
.negative_sign = s_empty_string,
.int_frac_digits = CHAR_MAX,
.frac_digits = CHAR_MAX,
.p_cs_precedes = CHAR_MAX,
.p_sep_by_space = CHAR_MAX,
.n_cs_precedes = CHAR_MAX,
.n_sep_by_space = CHAR_MAX,
.p_sign_posn = CHAR_MAX,
.n_sign_posn = CHAR_MAX,
};
extern "C" extern "C"
{ {
@ -9,4 +33,9 @@ extern "C"
// FIXME: Set the current locale if <locale> is not NULL. // FIXME: Set the current locale if <locale> is not NULL.
return s_default_locale; return s_default_locale;
} }
struct lconv* localeconv(void)
{
return &s_lconv;
}
} }

106
libc/src/math.cpp Normal file
View File

@ -0,0 +1,106 @@
#include <math.h>
// FIXME: Provide our own definitions instead of relying on the compiler's builtins.
#define WRAP_AROUND_BUILTIN(name) \
double name(double val) \
{ \
return __builtin_##name(val); \
} \
float name##f(float val) \
{ \
return __builtin_##name##f(val); \
} \
long double name##l(long double val) \
{ \
return __builtin_##name##l(val); \
}
#define WRAP_AROUND_BUILTIN2(name) \
double name(double val1, double val2) \
{ \
return __builtin_##name(val1, val2); \
} \
float name##f(float val1, float val2) \
{ \
return __builtin_##name##f(val1, val2); \
} \
long double name##l(long double val1, long double val2) \
{ \
return __builtin_##name##l(val1, val2); \
}
#define WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(name, type) \
double name(double val1, type val2) \
{ \
return __builtin_##name(val1, val2); \
} \
float name##f(float val1, type val2) \
{ \
return __builtin_##name##f(val1, val2); \
} \
long double name##l(long double val1, type val2) \
{ \
return __builtin_##name##l(val1, val2); \
}
#define WRAP_AROUND_BUILTIN_WITH_POINTER(name) \
double name(double val1, double* val2) \
{ \
return __builtin_##name(val1, val2); \
} \
float name##f(float val1, float* val2) \
{ \
return __builtin_##name##f(val1, val2); \
} \
long double name##l(long double val1, long double* val2) \
{ \
return __builtin_##name##l(val1, val2); \
}
extern "C"
{
WRAP_AROUND_BUILTIN(cos);
WRAP_AROUND_BUILTIN(sin);
WRAP_AROUND_BUILTIN(tan);
WRAP_AROUND_BUILTIN(acos);
WRAP_AROUND_BUILTIN(asin);
WRAP_AROUND_BUILTIN(atan);
WRAP_AROUND_BUILTIN(cosh);
WRAP_AROUND_BUILTIN(sinh);
WRAP_AROUND_BUILTIN(tanh);
WRAP_AROUND_BUILTIN(log);
WRAP_AROUND_BUILTIN(exp);
WRAP_AROUND_BUILTIN(sqrt);
WRAP_AROUND_BUILTIN(fabs);
WRAP_AROUND_BUILTIN(floor);
WRAP_AROUND_BUILTIN(ceil);
WRAP_AROUND_BUILTIN(log10);
WRAP_AROUND_BUILTIN2(fmod);
WRAP_AROUND_BUILTIN2(pow);
WRAP_AROUND_BUILTIN2(atan2);
WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(frexp, int*);
WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(ldexp, int);
WRAP_AROUND_BUILTIN_WITH_POINTER(modf);
}

View File

@ -752,4 +752,13 @@ extern "C"
{ {
setvbuf(stream, NULL, _IOLBF, 0); setvbuf(stream, NULL, _IOLBF, 0);
} }
int rename(const char* oldpath, const char* newpath)
{
// FIXME: Implement this atomically in-kernel.
unlink(newpath);
if (link(oldpath, newpath) < 0) return -1;
unlink(oldpath);
return 0;
}
} }

View File

@ -15,6 +15,12 @@ extern "C"
return strcmp(a, b); return strcmp(a, b);
} }
size_t strxfrm(char* dest, const char* src, size_t n)
{
strncpy(dest, src, n);
return n;
}
char* strerror(int errnum) char* strerror(int errnum)
{ {
return const_cast<char*>(error_string(errnum)); return const_cast<char*>(error_string(errnum));

View File

@ -11,13 +11,13 @@ extern "C"
__errno_return(rc, int); __errno_return(rc, int);
} }
int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen) int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen)
{ {
long rc = syscall(SYS_bind, sockfd, addr, addrlen); long rc = syscall(SYS_bind, sockfd, addr, addrlen);
__errno_return(rc, int); __errno_return(rc, int);
} }
int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen) int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen)
{ {
long rc = syscall(SYS_connect, sockfd, addr, addrlen); long rc = syscall(SYS_connect, sockfd, addr, addrlen);
__errno_return(rc, int); __errno_return(rc, int);

View File

@ -3,6 +3,7 @@
#include <luna/Format.h> #include <luna/Format.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/resource.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
@ -31,6 +32,13 @@ static int day_of_week(int year, int mon, int day)
return (year + year / 4 - year / 100 + year / 400 + t[mon - 1] + day) % 7; return (year + year / 4 - year / 100 + year / 400 + t[mon - 1] + day) % 7;
} }
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16
static constexpr u64 broken_down_to_unix(u64 year, u64 yday, u64 hour, u64 min, u64 sec)
{
return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 -
((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400;
}
static void time_to_struct_tm(time_t time, struct tm* result) static void time_to_struct_tm(time_t time, struct tm* result)
{ {
result->tm_isdst = 0; // No DST/timezone support for now. result->tm_isdst = 0; // No DST/timezone support for now.
@ -167,4 +175,29 @@ extern "C"
return 0; return 0;
} }
time_t mktime(struct tm* tm)
{
// FIXME: Check if the tm structure is valid.
time_t result = broken_down_to_unix(tm->tm_year, make_yday(tm->tm_year, tm->tm_mon + 1) + (tm->tm_mday - 1),
tm->tm_hour, tm->tm_min, tm->tm_sec);
tm->tm_yday = make_yday(tm->tm_year + 1900, tm->tm_mon + 1) + (tm->tm_mday - 1);
tm->tm_wday = day_of_week(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
return result;
}
double difftime(time_t a, time_t b)
{
return (double)(a - b);
}
clock_t clock(void)
{
struct rusage ru;
if (getrusage(RUSAGE_SELF, &ru) < 0) return (clock_t)-1;
return ru.ru_utime.tv_sec * CLOCKS_PER_SEC + ru.ru_utime.tv_usec;
}
} }

View File

@ -8,6 +8,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/utsname.h> #include <sys/utsname.h>
@ -510,4 +511,20 @@ extern "C"
long rc = syscall(SYS_ftruncate, fd, size); long rc = syscall(SYS_ftruncate, fd, size);
__errno_return(rc, int); __errno_return(rc, int);
} }
int getpagesize(void)
{
return PAGE_SIZE;
}
unsigned int alarm(unsigned int seconds)
{
return (unsigned int)syscall(SYS_alarm, seconds);
}
int pledge(const char* promises, const char* execpromises)
{
long rc = syscall(SYS_pledge, promises, execpromises);
__errno_return(rc, int);
}
} }

View File

@ -8,7 +8,7 @@
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \ _e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \ _e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \ _e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
_e(truncate) _e(ftruncate) _e(utimensat) _e(truncate) _e(ftruncate) _e(utimensat) _e(alarm) _e(pledge)
enum Syscalls enum Syscalls
{ {

View File

@ -1,62 +1,70 @@
#pragma once #pragma once
#define EPERM 1 // Operation not permitted #define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory #define ENOENT 2 // No such file or directory
#define ESRCH 3 // No such process #define ESRCH 3 // No such process
#define EINTR 4 // Interrupted system call #define EINTR 4 // Interrupted system call
#define EIO 5 // Input/output error #define EIO 5 // Input/output error
#define ENXIO 6 // No such device or address #define ENXIO 6 // No such device or address
#define E2BIG 7 // Argument list too long #define E2BIG 7 // Argument list too long
#define ENOEXEC 8 // Exec format error #define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor #define EBADF 9 // Bad file descriptor
#define ECHILD 10 // No child processes #define ECHILD 10 // No child processes
#define EAGAIN 11 // Resource temporarily unavailable #define EAGAIN 11 // Resource temporarily unavailable
#define EWOULDBLOCK 11 // Resource temporarily unavailable #define EWOULDBLOCK 11 // Resource temporarily unavailable
#define ENOMEM 12 // Cannot allocate memory #define ENOMEM 12 // Cannot allocate memory
#define EACCES 13 // Permission denied #define EACCES 13 // Permission denied
#define EFAULT 14 // Bad address #define EFAULT 14 // Bad address
#define ENOTBLK 15 // Block device required #define ENOTBLK 15 // Block device required
#define EBUSY 16 // Device or resource busy #define EBUSY 16 // Device or resource busy
#define EEXIST 17 // File exists #define EEXIST 17 // File exists
#define EXDEV 18 // Invalid cross-device link #define EXDEV 18 // Invalid cross-device link
#define ENODEV 19 // No such device #define ENODEV 19 // No such device
#define ENOTDIR 20 // Not a directory #define ENOTDIR 20 // Not a directory
#define EISDIR 21 // Is a directory #define EISDIR 21 // Is a directory
#define EINVAL 22 // Invalid argument #define EINVAL 22 // Invalid argument
#define ENFILE 23 // Too many open files in system #define ENFILE 23 // Too many open files in system
#define EMFILE 24 // Too many open files #define EMFILE 24 // Too many open files
#define ENOTTY 25 // Inappropriate ioctl for device #define ENOTTY 25 // Inappropriate ioctl for device
#define ETXTBSY 26 // Text file busy #define ETXTBSY 26 // Text file busy
#define EFBIG 27 // File too large #define EFBIG 27 // File too large
#define ENOSPC 28 // No space left on device #define ENOSPC 28 // No space left on device
#define ESPIPE 29 // Illegal seek #define ESPIPE 29 // Illegal seek
#define EROFS 30 // Read-only file system #define EROFS 30 // Read-only file system
#define EMLINK 31 // Too many links #define EMLINK 31 // Too many links
#define EPIPE 32 // Broken pipe #define EPIPE 32 // Broken pipe
#define EDOM 33 // Numerical argument out of domain #define EDOM 33 // Numerical argument out of domain
#define ERANGE 34 // Numerical result out of range #define ERANGE 34 // Numerical result out of range
#define EDEADLK 35 // Resource deadlock avoided #define EDEADLK 35 // Resource deadlock avoided
#define ENAMETOOLONG 36 // File name too long #define ENAMETOOLONG 36 // File name too long
#define ENOLCK 37 // No locks available #define ENOLCK 37 // No locks available
#define ENOSYS 38 // Function not implemented #define ENOSYS 38 // Function not implemented
#define ENOTEMPTY 39 // Directory not empty #define ENOTEMPTY 39 // Directory not empty
#define ELOOP 40 // Too many levels of symbolic links #define ELOOP 40 // Too many levels of symbolic links
#define ENOMSG 42 // No message of desired type #define ENOMSG 42 // No message of desired type
#define EOVERFLOW 75 // Value too large for defined data type #define EOVERFLOW 75 // Value too large for defined data type
#define EILSEQ 84 // Invalid or incomplete multibyte or wide character #define EILSEQ 84 // Invalid or incomplete multibyte or wide character
#define ENOTSOCK 88 // Socket operation on non-socket #define ENOTSOCK 88 // Socket operation on non-socket
#define EDESTADDRREQ 89 // Destination address required #define EDESTADDRREQ 89 // Destination address required
#define EPROTOTYPE 91 // Protocol wrong type for socket #define EMSGSIZE 90 // Message too long
#define ENOTSUP 95 // Operation not supported #define EPROTOTYPE 91 // Protocol wrong type for socket
#define EOPNOTSUPP 95 // Operation not supported #define ENOPROTOOPT 92 // Protocol not available
#define EAFNOSUPPORT 97 // Address family not supported by protocol #define EPROTONOSUPPORT 93 // Protocol not supported
#define EADDRINUSE 98 // Address already in use #define ENOTSUP 95 // Operation not supported
#define EADDRNOTAVAIL 99 // Cannot assign requested address #define EOPNOTSUPP 95 // Operation not supported
#define ENETRESET 102 // Network dropped connection on reset #define EAFNOSUPPORT 97 // Address family not supported by protocol
#define ECONNRESET 104 // Connection reset by peer #define EADDRINUSE 98 // Address already in use
#define EISCONN 106 // Transport endpoint is already connected #define EADDRNOTAVAIL 99 // Cannot assign requested address
#define ENOTCONN 107 // Transport endpoint is not connected #define ENETDOWN 100 // Network is down
#define ETIMEDOUT 110 // Connection timed out #define ENETUNREACH 101 // Network is unreachable
#define ECONNREFUSED 111 // Connection refused #define ENETRESET 102 // Network dropped connection on reset
#define EALREADY 114 // Operation already in progress #define ECONNABORTED 103 // Software caused connection abort
#define EINPROGRESS 115 // Operation now in progress #define ECONNRESET 104 // Connection reset by peer
#define ENOBUFS 105 // No buffer space available
#define EISCONN 106 // Transport endpoint is already connected
#define ENOTCONN 107 // Transport endpoint is not connected
#define ETIMEDOUT 110 // Connection timed out
#define ECONNREFUSED 111 // Connection refused
#define EHOSTUNREACH 113 // No route to host
#define EALREADY 114 // Operation already in progress
#define EINPROGRESS 115 // Operation now in progress

View File

@ -17,10 +17,14 @@
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
// Otherwise, this is defined in libstdc++.
#ifdef USE_FREESTANDING
namespace std namespace std
{ {
const nothrow_t nothrow; const nothrow_t nothrow;
} }
#endif
static constexpr int BLOCK_USED = 1 << 0; static constexpr int BLOCK_USED = 1 << 0;
static constexpr int BLOCK_START_MEM = 1 << 1; static constexpr int BLOCK_START_MEM = 1 << 1;
@ -417,6 +421,8 @@ void dump_heap_usage()
dbgln("-- Heap memory in use: %zu bytes", alloc_used); dbgln("-- Heap memory in use: %zu bytes", alloc_used);
} }
// Otherwise, this is defined in libstdc++.
#ifdef USE_FREESTANDING
void* operator new(usize size, const std::nothrow_t&) noexcept void* operator new(usize size, const std::nothrow_t&) noexcept
{ {
return malloc_impl(size).value_or(nullptr); return malloc_impl(size).value_or(nullptr);
@ -446,3 +452,4 @@ void operator delete[](void* p, usize) noexcept
{ {
free_impl(p); free_impl(p);
} }
#endif

View File

@ -63,6 +63,14 @@ const char* error_string(int error)
case EADDRNOTAVAIL: return "Cannot assign requested address"; case EADDRNOTAVAIL: return "Cannot assign requested address";
case ECONNREFUSED: return "Connection refused"; case ECONNREFUSED: return "Connection refused";
case EINPROGRESS: return "Operation now in progress"; case EINPROGRESS: return "Operation now in progress";
case ECONNABORTED: return "Software caused connection abort";
case EHOSTUNREACH: return "No route to host";
case EMSGSIZE: return "Message too long";
case ENETDOWN: return "Network is down";
case ENETUNREACH: return "Network is unreachable";
case ENOBUFS: return "No buffer space available";
case ENOPROTOOPT: return "Protocol not available";
case EPROTONOSUPPORT: return "Protocol not supported";
default: return "Unknown error"; default: return "Unknown error";
} }
} }
@ -132,6 +140,14 @@ const char* error_name(int error)
ERROR(EADDRNOTAVAIL); ERROR(EADDRNOTAVAIL);
ERROR(ECONNREFUSED); ERROR(ECONNREFUSED);
ERROR(EINPROGRESS); ERROR(EINPROGRESS);
ERROR(ECONNABORTED);
ERROR(EHOSTUNREACH);
ERROR(EMSGSIZE);
ERROR(ENETDOWN);
ERROR(ENETUNREACH);
ERROR(ENOBUFS);
ERROR(ENOPROTOOPT);
ERROR(EPROTONOSUPPORT);
default: return nullptr; default: return nullptr;
} }

View File

@ -13,6 +13,7 @@ set(SOURCES
src/Path.cpp src/Path.cpp
src/Mode.cpp src/Mode.cpp
src/Prompt.cpp src/Prompt.cpp
src/Security.cpp
src/LocalServer.cpp src/LocalServer.cpp
src/LocalClient.cpp src/LocalClient.cpp
) )

View File

@ -0,0 +1,48 @@
/**
* @file Security.h
* @author apio (cloudapio.eu)
* @brief Functions to restrict process operations.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#pragma once
#include <luna/Result.h>
namespace os
{
namespace Security
{
/**
* @brief Restrict system operations.
*
* The pledge() call, borrowed from OpenBSD, is a simple function to sandbox a process effectively.
*
* Syscalls are divided into a number of categories ("promises"), the following are the ones implemented on
* Luna: stdio rpath wpath cpath fattr chown unix tty proc exec prot_exec id mount signal host error
*
* The way pledge() works is: the process "tells" the kernel which subset of functions it will use, and if it
* suddenly uses something it has not promised (probably because the process was hacked, using ROP or something
* else) the kernel kills the process immediately with an uncatchable SIGABRT. Alternatively, if the process has
* pledged the "error" promise, the call will fail with ENOSYS.
*
* Pledges are not inherited across exec, although one may specify another set of promises to apply on the next
* execve() call. Thus, pledge() is not a way to restrict untrusted programs (unless the "exec" pledge is
* removed), but more of a way to protect trusted local programs from vulnerabilities.
*
* One may call pledge() several times, but only to remove promises, not to add them.
*
* A typical call to pledge would look like this:
*
* TRY(os::Security::pledge("stdio rpath wpath unix proc", nullptr));
*
* @param promises The promises to apply immediately, separated by spaces. If empty, the process may only call
* _exit(2). If NULL, the promises are not changed.
* @param execpromises The promises to apply on the next call to execve(2), separated by spaces. If empty, the
* process may only call _exit(2). If NULL, the execpromises are not changed.
* @return Result<void> Whether the operation succeded.
*/
Result<void> pledge(const char* promises, const char* execpromises);
}
}

22
libos/src/Security.cpp Normal file
View File

@ -0,0 +1,22 @@
/**
* @file Security.cpp
* @author apio (cloudapio.eu)
* @brief Functions to restrict process operations.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <errno.h>
#include <os/Security.h>
#include <unistd.h>
namespace os::Security
{
Result<void> pledge(const char* promises, const char* execpromises)
{
int rc = ::pledge(promises, execpromises);
if (rc < 0) return err(errno);
return {};
}
}

View File

@ -13,8 +13,11 @@ Name | Version | Description | URL
---|---|--- | --- ---|---|--- | ---
bc | 6.6.0 | An implementation of the POSIX bc calculator | https://github.com/gavinhoward/bc bc | 6.6.0 | An implementation of the POSIX bc calculator | https://github.com/gavinhoward/bc
binutils | 2.39 | The GNU suite of binary utilities | https://www.gnu.org/software/binutils binutils | 2.39 | The GNU suite of binary utilities | https://www.gnu.org/software/binutils
gmp | 6.3.0 | The GNU Multiple Precision Arithmetic Library | https://gmplib.org
minitar | 1.7.5 | Tiny and easy-to-use C library to read/write tar archives | https://git.cloudapio.eu/apio/minitar minitar | 1.7.5 | Tiny and easy-to-use C library to read/write tar archives | https://git.cloudapio.eu/apio/minitar
nasm | 2.16.01 | An assembler for the x86 CPU architecture | https://nasm.us mpc | 1.3.1 | The GNU Multiple Precision Complex Library | https://www.multiprecision.org
mpfr | 4.2.0 | The GNU Multiple Precision Floating-Point Reliable Library | https://mpfr.org
nasm | 2.16.01 | An assembler for the x86 CPU architecture | https://nasm.us
## Installing ports ## Installing ports
@ -48,10 +51,13 @@ The `name` variable should be set to the name of the ported program.
The `version` variable should be set to the currently ported version of the program. The `version` variable should be set to the currently ported version of the program.
If the program has dependencies on any other library/program, the `dependencies` field should be set to a list of those. Note that these dependencies must also be ported to Luna! Thus, when porting programs, you'll have to start with porting their dependencies (unless those have already been ported).
Example: Example:
``` ```
name="example" name="example"
version="1.0.0" version="1.0.0"
dependencies=(foo bar)
``` ```
#### Download options #### Download options

View File

@ -10,6 +10,7 @@ sha256sum="d12ea6f239f1ffe3533ea11ad6e224ffcb89eb5d01bbea589e9158780fa11f10"
# Build instructions # Build instructions
default_build_make=true default_build_make=true
default_install_make=true
do_patch() do_patch()
{ {
@ -18,13 +19,5 @@ do_patch()
do_configure() do_configure()
{ {
$srcdir/configure --host=$LUNA_ARCH-luna --disable-nls --disable-werror --enable-warn-rwx-segments=no --prefix=/usr --enable-gold=no --enable-ld=yes --enable-gprofng=no $srcdir/configure --host=$LUNA_ARCH-luna --with-build-sysroot=$LUNA_BASE --disable-nls --disable-werror --enable-warn-rwx-segments=no --prefix=/usr --enable-gold=no --enable-ld=yes --enable-gprofng=no
}
do_install()
{
make install
cd $installdir/usr/bin
$LUNA_ARCH-luna-strip size objdump ar strings ranlib objcopy addr2line readelf elfedit nm strip c++filt as gprof ld.bfd ld
} }

18
ports/gmp/PACKAGE Normal file
View File

@ -0,0 +1,18 @@
# Basic information
name="gmp"
version="6.3.0"
# Download options
format="tar"
url="https://gmplib.org/download/gmp/gmp-$version.tar.xz"
output="gmp-$version.tar.xz"
sha256sum="a3c2b80201b89e68616f4ad30bc66aee4927c3ce50e33929ca819d5c43538898"
# Build instructions
default_build_make=true
default_install_make=true
do_configure()
{
$srcdir/configure --enable-shared=no --with-gnu-ld --host=$LUNA_ARCH-luna --prefix=/usr
}

19
ports/mpc/PACKAGE Normal file
View File

@ -0,0 +1,19 @@
# Basic information
name="mpc"
version="1.3.1"
dependencies=(gmp mpfr)
# Download options
format="tar"
url="https://ftp.gnu.org/gnu/mpc/mpc-$version.tar.gz"
output="mpc-$version.tar.gz"
sha256sum="ab642492f5cf882b74aa0cb730cd410a81edcdbec895183ce930e706c1c759b8"
# Build instructions
default_build_make=true
default_install_make=true
do_configure()
{
$srcdir/configure --enable-shared=no --with-gnu-ld --host=$LUNA_ARCH-luna --prefix=/usr
}

19
ports/mpfr/PACKAGE Normal file
View File

@ -0,0 +1,19 @@
# Basic information
name="mpfr"
version="4.2.0"
dependencies=(gmp)
# Download options
format="tar"
url="https://www.mpfr.org/mpfr-current/mpfr-$version.tar.gz"
output="mpfr-$version.tar.gz"
sha256sum="f1cc1c6bb14d18f0c61cc416e083f5e697b6e0e3cf9630b9b33e8e483fc960f0"
# Build instructions
default_build_make=true
default_install_make=true
do_configure()
{
$srcdir/configure --enable-shared=no --with-gnu-ld --host=$LUNA_ARCH-luna --prefix=/usr
}

View File

@ -72,6 +72,35 @@ TestResult test_setenv_before_and_after_manual_environ_modification()
test_success; test_success;
} }
TestResult test_putenv()
{
clearenv();
char lit[] = "NAME=VALUE";
validate(putenv(lit) == 0);
char* value = getenv("NAME");
validate(value && !strcmp(value, "VALUE"));
lit[0] = 'F';
value = getenv("NAME");
validate(!value);
value = getenv("FAME");
validate(value && !strcmp(value, "VALUE"));
validate(unsetenv("FAME") == 0);
value = getenv("FAME");
validate(!value);
validate(!strcmp(lit, "FAME=VALUE"));
test_success;
}
Result<void> test_main() Result<void> test_main()
{ {
test_prelude; test_prelude;
@ -80,6 +109,7 @@ Result<void> test_main()
run_test(test_setenv_dont_overwrite); run_test(test_setenv_dont_overwrite);
run_test(test_unsetenv); run_test(test_unsetenv);
run_test(test_setenv_before_and_after_manual_environ_modification); run_test(test_setenv_before_and_after_manual_environ_modification);
run_test(test_putenv);
return {}; return {};
} }

View File

@ -5,7 +5,7 @@ export LUNA_BASE=${LUNA_BASE:-$LUNA_ROOT/base}
[ -f "$LUNA_ROOT/env-local.sh" ] && source $LUNA_ROOT/env-local.sh [ -f "$LUNA_ROOT/env-local.sh" ] && source $LUNA_ROOT/env-local.sh
export LUNA_ARCH=${LUNA_ARCH:-x86_64} export LUNA_ARCH=${LUNA_ARCH:-x86_64}
export PATH=$LUNA_ROOT/toolchain/$LUNA_ARCH-luna/bin:$LUNA_ROOT/toolchain/dist:$PATH export PATH=$LUNA_ROOT/toolchain/$LUNA_ARCH-luna/bin:$LUNA_ROOT/toolchain/dist:$LUNA_ROOT/tools/exec/:$PATH
if [ "$USE_MAKE" = "1" ] if [ "$USE_MAKE" = "1" ]
then then

View File

@ -0,0 +1,10 @@
#!/bin/sh
# Fill these in appropriately:
export PKG_CONFIG_SYSROOT_DIR=$LUNA_BASE
export PKG_CONFIG_LIBDIR=$LUNA_BASE/usr/lib/pkgconfig
# TODO: If it works this should probably just be set to the empty string.
export PKG_CONFIG_PATH=$PKG_CONFIG_LIBDIR
# Use --static here if your OS only has static linking.
# TODO: Perhaps it's a bug in the libraries if their pkg-config files doesn't
# record that only static libraries were built.
exec pkg-config --static "$@"

View File

@ -1,6 +1,6 @@
diff --color -rN -u gcc-12.2.0/config.sub build/gcc-12.2.0/config.sub diff --color -rN -u vanilla/gcc-12.2.0/config.sub gcc-12.2.0/config.sub
--- a/gcc-12.2.0/config.sub 2022-08-19 10:09:52.128656687 +0200 --- a/gcc-12.2.0/config.sub 2022-08-19 10:09:52.128656687 +0200
+++ b/gcc-12.2.0/config.sub 2022-10-02 11:27:45.660055384 +0200 +++ b/gcc-12.2.0/config.sub 2023-08-08 20:42:05.032843544 +0200
@@ -1723,7 +1723,7 @@ @@ -1723,7 +1723,7 @@
| hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
| sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
@ -10,9 +10,9 @@ diff --color -rN -u gcc-12.2.0/config.sub build/gcc-12.2.0/config.sub
| mpw* | magic* | mmixware* | mon960* | lnews* \ | mpw* | magic* | mmixware* | mon960* | lnews* \
| amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
| aos* | aros* | cloudabi* | sortix* | twizzler* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \
diff --color -rN -u gcc-12.2.0/fixincludes/mkfixinc.sh build/gcc-12.2.0/fixincludes/mkfixinc.sh diff --color -rN -u vanilla/gcc-12.2.0/fixincludes/mkfixinc.sh gcc-12.2.0/fixincludes/mkfixinc.sh
--- a/gcc-12.2.0/fixincludes/mkfixinc.sh 2022-08-19 10:09:52.160657095 +0200 --- a/gcc-12.2.0/fixincludes/mkfixinc.sh 2022-08-19 10:09:52.160657095 +0200
+++ b/gcc-12.2.0/fixincludes/mkfixinc.sh 2022-10-02 11:27:45.662055397 +0200 +++ b/gcc-12.2.0/fixincludes/mkfixinc.sh 2023-08-08 20:42:05.034843561 +0200
@@ -12,6 +12,8 @@ @@ -12,6 +12,8 @@
# Check for special fix rules for particular targets # Check for special fix rules for particular targets
case $machine in case $machine in
@ -22,18 +22,18 @@ diff --color -rN -u gcc-12.2.0/fixincludes/mkfixinc.sh build/gcc-12.2.0/fixinclu
i?86-*-mingw32* | \ i?86-*-mingw32* | \
x86_64-*-mingw32* | \ x86_64-*-mingw32* | \
powerpc-*-eabisim* | \ powerpc-*-eabisim* | \
diff --color -rN -u gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel build/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel diff --color -rN -u vanilla/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel
--- a/dev/null 1970-01-01 01:00:00.000000000 +0100 --- a/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel 1970-01-01 01:00:00.000000000 +0100
+++ b/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel 2022-10-02 11:45:30.955856133 +0200 +++ b/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel 2023-08-08 20:42:05.038843594 +0200
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
+#Add libgcc multilib variant without red-zone requirement, for use in the kernel +#Add libgcc multilib variant without red-zone requirement, for use in the kernel
+ +
+MULTILIB_OPTIONS += mno-red-zone +MULTILIB_OPTIONS += mno-red-zone
+MULTILIB_DIRNAMES += no-red-zone +MULTILIB_DIRNAMES += no-red-zone
\ No newline at end of file \ No newline at end of file
diff --color -rN -u gcc-12.2.0/gcc/config/luna.h build/gcc-12.2.0/gcc/config/luna.h diff --color -rN -u vanilla/gcc-12.2.0/gcc/config/luna.h gcc-12.2.0/gcc/config/luna.h
--- a/dev/null 1970-01-01 01:00:00.000000000 +0100 --- a/gcc-12.2.0/gcc/config/luna.h 1970-01-01 01:00:00.000000000 +0100
+++ b/gcc-12.2.0/gcc/config/luna.h 2022-10-02 11:27:45.663055404 +0200 +++ b/gcc-12.2.0/gcc/config/luna.h 2023-08-08 20:42:05.040843610 +0200
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
+#undef TARGET_LUNA +#undef TARGET_LUNA
+#define TARGET_LUNA 1 +#define TARGET_LUNA 1
@ -71,11 +71,9 @@ diff --color -rN -u gcc-12.2.0/gcc/config/luna.h build/gcc-12.2.0/gcc/config/lun
+ } while (0); + } while (0);
+ +
+#undef LINK_SPEC +#undef LINK_SPEC
+#define LINK_SPEC "-z max-page-size=4096" diff --color -rN -u vanilla/gcc-12.2.0/gcc/config.gcc gcc-12.2.0/gcc/config.gcc
\ No newline at end of file
diff --color -rN -u gcc-12.2.0/gcc/config.gcc build/gcc-12.2.0/gcc/config.gcc
--- a/gcc-12.2.0/gcc/config.gcc 2022-08-19 10:09:52.552662114 +0200 --- a/gcc-12.2.0/gcc/config.gcc 2022-08-19 10:09:52.552662114 +0200
+++ b/gcc-12.2.0/gcc/config.gcc 2022-10-02 11:45:18.311797546 +0200 +++ b/gcc-12.2.0/gcc/config.gcc 2023-08-08 20:42:05.044843643 +0200
@@ -895,6 +895,12 @@ @@ -895,6 +895,12 @@
;; ;;
esac esac
@ -103,9 +101,9 @@ diff --color -rN -u gcc-12.2.0/gcc/config.gcc build/gcc-12.2.0/gcc/config.gcc
x86_64-*-rtems*) x86_64-*-rtems*)
tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h i386/rtemself.h rtems.h" tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h i386/rtemself.h rtems.h"
;; ;;
diff --color -rN -u gcc-12.2.0/libgcc/config.host build/gcc-12.2.0/libgcc/config.host diff --color -rN -u vanilla/gcc-12.2.0/libgcc/config.host gcc-12.2.0/libgcc/config.host
--- a/gcc-12.2.0/libgcc/config.host 2022-08-19 10:09:54.664689148 +0200 --- a/gcc-12.2.0/libgcc/config.host 2022-08-19 10:09:54.664689148 +0200
+++ b/gcc-12.2.0/libgcc/config.host 2022-10-02 11:27:45.671055461 +0200 +++ b/gcc-12.2.0/libgcc/config.host 2023-08-08 20:42:05.046843660 +0200
@@ -783,6 +783,14 @@ @@ -783,6 +783,14 @@
;; ;;
i[34567]86-*-lynxos*) i[34567]86-*-lynxos*)
@ -121,9 +119,9 @@ diff --color -rN -u gcc-12.2.0/libgcc/config.host build/gcc-12.2.0/libgcc/config
i[34567]86-*-nto-qnx*) i[34567]86-*-nto-qnx*)
tmake_file="$tmake_file i386/t-nto t-libgcc-pic" tmake_file="$tmake_file i386/t-nto t-libgcc-pic"
extra_parts=crtbegin.o extra_parts=crtbegin.o
diff --color -rN -u gcc-12.2.0/libgcc/libgcov.h build/gcc-12.2.0/libgcc/libgcov.h diff --color -rN -u vanilla/gcc-12.2.0/libgcc/libgcov.h gcc-12.2.0/libgcc/libgcov.h
--- a/gcc-12.2.0/libgcc/libgcov.h 2022-08-19 10:09:54.728689966 +0200 --- a/gcc-12.2.0/libgcc/libgcov.h 2022-08-19 10:09:54.728689966 +0200
+++ b/gcc-12.2.0/libgcc/libgcov.h 2022-10-02 11:41:48.571807335 +0200 +++ b/gcc-12.2.0/libgcc/libgcov.h 2023-08-08 20:42:05.048843677 +0200
@@ -194,6 +194,7 @@ @@ -194,6 +194,7 @@
#endif #endif
@ -132,3 +130,79 @@ diff --color -rN -u gcc-12.2.0/libgcc/libgcov.h build/gcc-12.2.0/libgcc/libgcov.
/* Structures embedded in coveraged program. The structures generated /* Structures embedded in coveraged program. The structures generated
by write_profile must match these. */ by write_profile must match these. */
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/acinclude.m4 gcc-12.2.0/libstdc++-v3/acinclude.m4
--- a/gcc-12.2.0/libstdc++-v3/acinclude.m4 2022-08-19 10:09:55.380698313 +0200
+++ b/gcc-12.2.0/libstdc++-v3/acinclude.m4 2023-08-08 21:08:00.777765701 +0200
@@ -1356,6 +1356,10 @@
ac_has_nanosleep=yes
ac_has_sched_yield=yes
;;
+ luna*)
+ ac_has_clock_monotonic=yes
+ ac_has_clock_realtime=yes
+ ;;
# VxWorks has nanosleep as soon as the kernel is configured with
# INCLUDE_POSIX_TIMERS, which is normally/most-often the case.
vxworks*)
@@ -2421,7 +2425,7 @@
dragonfly* | freebsd*)
enable_clocale_flag=dragonfly
;;
- openbsd*)
+ openbsd* | luna*)
enable_clocale_flag=newlib
;;
*)
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/configure gcc-12.2.0/libstdc++-v3/configure
--- a/gcc-12.2.0/libstdc++-v3/configure 2022-08-19 10:09:55.416698774 +0200
+++ b/gcc-12.2.0/libstdc++-v3/configure 2023-08-09 11:34:54.810282202 +0200
@@ -16481,6 +16481,9 @@
openbsd*)
enable_clocale_flag=newlib
;;
+ luna*)
+ enable_clocale_flag=generic
+ ;;
*)
if test x"$with_newlib" = x"yes"; then
enable_clocale_flag=newlib
@@ -20493,6 +20496,10 @@
ac_has_nanosleep=yes
ac_has_sched_yield=yes
;;
+ luna*)
+ ac_has_clock_monotonic=yes
+ ac_has_clock_realtime=yes
+ ;;
# VxWorks has nanosleep as soon as the kernel is configured with
# INCLUDE_POSIX_TIMERS, which is normally/most-often the case.
vxworks*)
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/configure.host gcc-12.2.0/libstdc++-v3/configure.host
--- a/gcc-12.2.0/libstdc++-v3/configure.host 2022-08-19 10:09:55.420698825 +0200
+++ b/gcc-12.2.0/libstdc++-v3/configure.host 2023-08-09 11:35:05.734185945 +0200
@@ -306,6 +306,9 @@
vxworks*)
os_include_dir="os/vxworks"
;;
+ luna*)
+ os_include_dir="os/generic"
+ ;;
*)
os_include_dir="os/generic"
;;
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/crossconfig.m4 gcc-12.2.0/libstdc++-v3/crossconfig.m4
--- a/gcc-12.2.0/libstdc++-v3/crossconfig.m4 2022-08-19 10:09:55.420698825 +0200
+++ b/gcc-12.2.0/libstdc++-v3/crossconfig.m4 2023-08-08 21:16:12.897071194 +0200
@@ -277,6 +277,12 @@
GLIBCXX_CHECK_MATH_SUPPORT
GLIBCXX_CHECK_STDLIB_SUPPORT
;;
+ *-luna*)
+ GLIBCXX_CHECK_COMPILER_FEATURES
+ GLIBCXX_CHECK_LINKER_FEATURES
+ GLIBCXX_CHECK_MATH_SUPPORT
+ GLIBCXX_CHECK_STDLIB_SUPPORT
+ ;;
*-vxworks*)
AC_DEFINE(HAVE_ACOSF)
AC_DEFINE(HAVE_ASINF)

View File

@ -15,16 +15,23 @@ fi
source ports/$PORT_NAME/PACKAGE source ports/$PORT_NAME/PACKAGE
IS_NEW_VERSION=0
if ! [ -f ports/out/$name-$version.tar.gz ]; then if ! [ -f ports/out/$name-$version.tar.gz ]; then
tools/make-package.sh $PORT_NAME tools/make-package.sh $PORT_NAME
IS_NEW_VERSION=1
fi fi
PORT_FILES=$LUNA_BASE/usr/share/pkgdb/$PORT_NAME.files PORT_FILES=$LUNA_BASE/usr/share/pkgdb/$name.files
if [ -f $PORT_FILES ] if [ -f $PORT_FILES ]
then then
echo "Package $PORT_NAME is already installed! Updating." if [ "$IS_NEW_VERSION" -eq "0" ]; then
tools/uninstall-package.sh $PORT_NAME echo "Package $PORT_NAME version $version is already installed!"
exit 0
fi
echo "Package $PORT_NAME is already installed! Updating to version $version."
tools/uninstall-package.sh $name
fi fi
mkdir -p $LUNA_BASE/usr/share/pkgdb/ mkdir -p $LUNA_BASE/usr/share/pkgdb/

View File

@ -28,6 +28,13 @@ source ports/$PORT_NAME/PACKAGE
[ -z ${format+x} ] && show_error "error: The port's PACKAGE file does not have a 'format' key." [ -z ${format+x} ] && show_error "error: The port's PACKAGE file does not have a 'format' key."
[ -z ${url+x} ] && show_error "error: The port's PACKAGE file does not have a 'url' key." [ -z ${url+x} ] && show_error "error: The port's PACKAGE file does not have a 'url' key."
if ! [ -z ${dependencies+x} ]; then
echo "Installing dependencies of $name: (${dependencies[@]})"
for dep in ${dependencies[@]}; do
tools/install-package.sh $dep
done
fi
export portdir=$LUNA_ROOT/ports/$name/ export portdir=$LUNA_ROOT/ports/$name/
export srcdir=${srcdir:-$WORKDIR/$name-$version} export srcdir=${srcdir:-$WORKDIR/$name-$version}
export builddir=$WORKDIR/build-$name export builddir=$WORKDIR/build-$name
@ -41,15 +48,22 @@ case $format in
tar) tar)
[ -z ${output+x} ] && show_error "error: The 'tar' download format needs an 'output' key." [ -z ${output+x} ] && show_error "error: The 'tar' download format needs an 'output' key."
[ -z ${sha256sum+x} ] && show_error "error: The 'tar' download format needs a 'sha256sum' key." [ -z ${sha256sum+x} ] && show_error "error: The 'tar' download format needs a 'sha256sum' key."
echo "Downloading tarball for $name..." if ! [ -f $output ]; then
wget $url --quiet echo "Downloading tarball for $name..."
wget $url --quiet
else
echo "Using cached tarball for $name."
fi
echo "$sha256sum $output" | sha256sum -c echo "$sha256sum $output" | sha256sum -c
tar xf $output tar xf $output
rm $output
;; ;;
git) git)
echo "Cloning repository for $name..." if ! [ -d $srcdir]; then
git clone $url $srcdir echo "Cloning repository for $name..."
git clone $url $srcdir
else
echo "Using local repository for $name."
fi
if ! [ -z ${tag+x} ]; then if ! [ -z ${tag+x} ]; then
cd $srcdir cd $srcdir
git checkout $tag git checkout $tag
@ -61,10 +75,14 @@ case $format in
;; ;;
esac esac
if ! [ "$set_cc_variables" = "no" ]; then
export CC=x86_64-luna-gcc export CC=x86_64-luna-gcc
export CXX=x86_64-luna-g++ export CXX=x86_64-luna-g++
export PKG_CONFIG=luna-pkg-config
export CC_FOR_BUILD=gcc export CC_FOR_BUILD=gcc
export CXX_FOR_BUILD=g++ export CXX_FOR_BUILD=g++
export PKG_CONFIG_FOR_BUILD=pkg-config
fi
mkdir -p $builddir mkdir -p $builddir
cd $builddir cd $builddir
@ -109,6 +127,11 @@ else
do_install do_install
fi fi
rm -f $installdir/usr/lib/*.la # remove all libtool .la files, as they use host stuff which we don't want at all
set +e
$LUNA_ARCH-luna-strip $installdir/usr/bin/* # strip all binaries
set -e
cd $installdir cd $installdir
tar czf $LUNA_ROOT/ports/out/$name-$version.tar.gz * tar czf $LUNA_ROOT/ports/out/$name-$version.tar.gz *

View File

@ -47,7 +47,7 @@ unset CXX
unset LD unset LD
unset AR unset AR
../gcc-$LUNA_GCC_VERSION_REQUIRED/configure --prefix="$BUILD_PREFIX" --target=$BUILD_TARGET --disable-nls --with-sysroot=$BUILD_SYSROOT --enable-languages=c,c++ --without-headers ../gcc-$LUNA_GCC_VERSION_REQUIRED/configure --prefix="$BUILD_PREFIX" --target=$BUILD_TARGET --disable-nls --with-sysroot=$BUILD_SYSROOT --enable-languages=c,c++
echo Building GCC... echo Building GCC...
@ -58,3 +58,10 @@ echo Installing GCC...
make install-gcc make install-gcc
make install-target-libgcc make install-target-libgcc
mkdir -p $LUNA_BUILD_DIR
cmake -S $LUNA_ROOT -B $LUNA_BUILD_DIR -G "$LUNA_CMAKE_GENERATOR_NAME"
cmake --build $LUNA_BUILD_DIR --target libc
make all-target-libstdc++-v3 CXXFLAGS_FOR_TARGET="-fno-exceptions" -j$(nproc)
make DESTDIR=$LUNA_BASE/usr install-target-libstdc++-v3

View File

@ -14,5 +14,7 @@ then
exit 1 exit 1
fi fi
set +e
rm -v $(cat $LUNA_BASE/usr/share/pkgdb/$PORT_NAME.files) rm -v $(cat $LUNA_BASE/usr/share/pkgdb/$PORT_NAME.files)
rm -v $LUNA_BASE/usr/share/pkgdb/$PORT_NAME.files rm -v $LUNA_BASE/usr/share/pkgdb/$PORT_NAME.files