From ac260d0397acedbae570aa728c5a5c75b9324823 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 13 Dec 2024 23:47:53 +0100 Subject: [PATCH] wind+libui: Add "pledge" functionality to access special features for system programs This segments privileges more, making it so that any app connecting to wsys.sock can't just always access every single advanced feature in wind if they don't need to. Of course, apps have to restrict themselves, which is why only privileged apps have access to this feature in the first place. Normal apps' pledges are all empty and can't be changed. An example: taskbar uses the "ExtendedLayers" pledge to move its window to the background, but relinquishes it afterwards, and doesn't need any other advanced feature for now. If a pledge-capable app tries to use a pledge-protected function without having pledged anything, it can't. Pledges are mandatory if you want to access certain functionality, unlike the kernel's pledges which make every syscall available if you don't use pledge(). --- gui/apps/taskbar.cpp | 2 ++ gui/libui/include/ui/App.h | 2 ++ gui/libui/include/ui/ipc/Server.h | 13 ++++++++ gui/libui/src/App.cpp | 7 +++++ gui/wind/CMakeLists.txt | 1 + gui/wind/Client.cpp | 52 +++++++++++++++++++++++++++++++ gui/wind/Client.h | 17 +++++----- gui/wind/IPC.cpp | 17 +++++++--- gui/wind/main.cpp | 5 ++- 9 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 gui/wind/Client.cpp diff --git a/gui/apps/taskbar.cpp b/gui/apps/taskbar.cpp index 6665dd1b..df2595c9 100644 --- a/gui/apps/taskbar.cpp +++ b/gui/apps/taskbar.cpp @@ -112,6 +112,7 @@ Result luna_main(int, char**) { ui::App app; TRY(app.init("/tmp/wsys.sock")); + app.pledge(ui::Pledge::ExtendedLayers); TRY(os::EventLoop::the().register_signal_handler(SIGQUIT, sigquit_handler)); @@ -126,6 +127,7 @@ Result luna_main(int, char**) window->set_background(TASKBAR_COLOR); window->set_layer(ui::Layer::Background); + app.pledge(0); ui::HorizontalLayout layout(ui::Margins { 0, 0, 0, 0 }, ui::AdjustHeight::Yes, ui::AdjustWidth::No); window->set_main_widget(layout); diff --git a/gui/libui/include/ui/App.h b/gui/libui/include/ui/App.h index ce1e2496..ca2794ee 100644 --- a/gui/libui/include/ui/App.h +++ b/gui/libui/include/ui/App.h @@ -49,6 +49,8 @@ namespace ui return m_main_window; } + void pledge(i16 pledges); + Result register_window(OwnedPtr&& window, Badge); void unregister_window(Window* window, Badge); diff --git a/gui/libui/include/ui/ipc/Server.h b/gui/libui/include/ui/ipc/Server.h index ae37d77c..62344b60 100644 --- a/gui/libui/include/ui/ipc/Server.h +++ b/gui/libui/include/ui/ipc/Server.h @@ -26,6 +26,7 @@ namespace ui GET_SCREEN_RECT_ID, SET_TITLEBAR_HEIGHT_ID, SET_WINDOW_LAYER_ID, + UPDATE_PLEDGE_REQUEST_ID, }; struct CreateWindowRequest @@ -97,4 +98,16 @@ namespace ui int window; Layer layer; }; + + enum Pledge : i16 + { + ExtendedLayers = 1, + }; + + struct UpdatePledgeRequest + { + static constexpr u8 ID = UPDATE_PLEDGE_REQUEST_ID; + + i16 pledges; + }; } diff --git a/gui/libui/src/App.cpp b/gui/libui/src/App.cpp index d53b17b7..f40bff49 100644 --- a/gui/libui/src/App.cpp +++ b/gui/libui/src/App.cpp @@ -135,4 +135,11 @@ namespace ui m_window_clear_queue.clear_data(); return !m_should_close; } + + void App::pledge(i16 pledges) + { + ui::UpdatePledgeRequest request; + request.pledges = pledges; + client().send_async(request); + } } diff --git a/gui/wind/CMakeLists.txt b/gui/wind/CMakeLists.txt index 85455a93..d31e0eed 100644 --- a/gui/wind/CMakeLists.txt +++ b/gui/wind/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES Keyboard.cpp Keyboard.h Client.h + Client.cpp Layer.cpp Layer.h ) diff --git a/gui/wind/Client.cpp b/gui/wind/Client.cpp new file mode 100644 index 00000000..4198ff4a --- /dev/null +++ b/gui/wind/Client.cpp @@ -0,0 +1,52 @@ +#include "Client.h" +#include + +Client::Client(OwnedPtr&& client, i16 _pledges) + : conn(move(client)), windows(), pledges(_pledges) +{ + conn->set_message_handler(wind::handle_ipc_message, this); +} + +bool Client::update_pledges(i16 _pledges) +{ + if (_pledges < 0) + { + os::eprintln("wind: Client trying to set an invalid pledge, disconnecting!"); + should_be_disconnected = true; + return false; + } + + if (pledges < 0) + { + pledges = _pledges; + return true; + } + + if (_pledges & ~pledges) + { + os::eprintln("wind: Client trying to add pledges, disconnecting!"); + should_be_disconnected = true; + return false; + } + + pledges = _pledges; + return true; +} + +bool Client::check_pledge(i16 pledge) +{ + check(pledge > 0); + + if (pledges < 0) + { + os::eprintln("wind: Client trying to use pledge-protected functions before pledging anything, disconnecting!"); + should_be_disconnected = true; + return false; + } + + if ((pledges & pledge) == pledge) return true; + + os::eprintln("wind: Client trying to use a function they haven't pledged, disconnecting!"); + should_be_disconnected = true; + return false; +} diff --git a/gui/wind/Client.h b/gui/wind/Client.h index ad3a0a7e..12cc1d2c 100644 --- a/gui/wind/Client.h +++ b/gui/wind/Client.h @@ -3,20 +3,19 @@ #include "Window.h" #include +constexpr i16 HAS_NOT_YET_PLEDGED = -1; +constexpr i16 EMPTY_PLEDGE = 0; + struct Client { OwnedPtr conn; Vector windows; const bool privileged { false }; bool should_be_disconnected { false }; + i16 pledges = 0; - Client(OwnedPtr&& client, bool priv) -#ifdef CLIENT_IMPLEMENTATION - : conn(move(client)), windows(), privileged(priv) - { - conn->set_message_handler(wind::handle_ipc_message, this); - } -#else - ; -#endif + bool update_pledges(i16 pledges); + bool check_pledge(i16 pledge); + + Client(OwnedPtr&& client, i16 pledges); }; diff --git a/gui/wind/IPC.cpp b/gui/wind/IPC.cpp index f879e20c..abe5c0b4 100644 --- a/gui/wind/IPC.cpp +++ b/gui/wind/IPC.cpp @@ -166,11 +166,9 @@ static Result handle_set_window_layer_message(Client& client) ui::SetWindowLayer request; if (!TRY(client.conn->read_message(request))) return {}; - if (request.layer != ui::Layer::Global && request.layer != ui::Layer::GlobalTop && !client.privileged) + if (request.layer != ui::Layer::Global && request.layer != ui::Layer::GlobalTop) { - os::eprintln("wind: Unprivileged client trying to set window layer to a privileged layer, disconnecting!"); - client.should_be_disconnected = true; - return {}; + if (!client.check_pledge(ui::Pledge::ExtendedLayers)) return {}; } CHECK_WINDOW_ID(request, "SetWindowLayer"); @@ -199,6 +197,16 @@ static Result handle_set_window_layer_message(Client& client) return {}; } +static Result handle_update_pledge_request_message(Client& client) +{ + ui::UpdatePledgeRequest request; + if (!TRY(client.conn->read_message(request))) return {}; + + client.update_pledges(request.pledges); // update_pledges does all the checking. + + return {}; +} + namespace wind { void handle_ipc_message(os::IPC::ClientConnection&, u8 id, void* c) @@ -214,6 +222,7 @@ namespace wind case ui::GET_SCREEN_RECT_ID: handle_get_screen_rect_message(client); break; case ui::SET_TITLEBAR_HEIGHT_ID: handle_set_titlebar_height_message(client); break; case ui::SET_WINDOW_LAYER_ID: handle_set_window_layer_message(client); break; + case ui::UPDATE_PLEDGE_REQUEST_ID: handle_update_pledge_request_message(client); break; default: os::eprintln("wind: Invalid IPC message from client!"); return; } } diff --git a/gui/wind/main.cpp b/gui/wind/main.cpp index bbebfc68..d35000d9 100644 --- a/gui/wind/main.cpp +++ b/gui/wind/main.cpp @@ -1,4 +1,3 @@ -#define CLIENT_IMPLEMENTATION #include "Client.h" #include "Keyboard.h" #include "Layer.h" @@ -138,7 +137,7 @@ Result luna_main(int argc, char** argv) auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client))); - OwnedPtr c = TRY(adopt_owned_if_nonnull(new Client(move(connection), false))); + OwnedPtr c = TRY(adopt_owned_if_nonnull(new Client(move(connection), EMPTY_PLEDGE))); TRY(clients.try_append(move(c))); } if (fds[3].revents & POLLIN) @@ -149,7 +148,7 @@ Result luna_main(int argc, char** argv) auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client))); - OwnedPtr c = TRY(adopt_owned_if_nonnull(new Client(move(connection), true))); + OwnedPtr c = TRY(adopt_owned_if_nonnull(new Client(move(connection), HAS_NOT_YET_PLEDGED))); TRY(clients.try_append(move(c))); } for (usize i = 0; i < clients.size(); i++)