wind+libui: Add "pledge" functionality to access special features for system programs
All checks were successful
Build and test / build (push) Successful in 1m42s

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().
This commit is contained in:
apio 2024-12-13 23:47:53 +01:00
parent fb3333a086
commit ac260d0397
Signed by: apio
GPG Key ID: B8A7D06E42258954
9 changed files with 100 additions and 16 deletions

View File

@ -112,6 +112,7 @@ Result<int> luna_main(int, char**)
{ {
ui::App app; ui::App app;
TRY(app.init("/tmp/wsys.sock")); TRY(app.init("/tmp/wsys.sock"));
app.pledge(ui::Pledge::ExtendedLayers);
TRY(os::EventLoop::the().register_signal_handler(SIGQUIT, sigquit_handler)); TRY(os::EventLoop::the().register_signal_handler(SIGQUIT, sigquit_handler));
@ -126,6 +127,7 @@ Result<int> luna_main(int, char**)
window->set_background(TASKBAR_COLOR); window->set_background(TASKBAR_COLOR);
window->set_layer(ui::Layer::Background); window->set_layer(ui::Layer::Background);
app.pledge(0);
ui::HorizontalLayout layout(ui::Margins { 0, 0, 0, 0 }, ui::AdjustHeight::Yes, ui::AdjustWidth::No); ui::HorizontalLayout layout(ui::Margins { 0, 0, 0, 0 }, ui::AdjustHeight::Yes, ui::AdjustWidth::No);
window->set_main_widget(layout); window->set_main_widget(layout);

View File

@ -49,6 +49,8 @@ namespace ui
return m_main_window; return m_main_window;
} }
void pledge(i16 pledges);
Result<void> register_window(OwnedPtr<Window>&& window, Badge<Window>); Result<void> register_window(OwnedPtr<Window>&& window, Badge<Window>);
void unregister_window(Window* window, Badge<Window>); void unregister_window(Window* window, Badge<Window>);

View File

@ -26,6 +26,7 @@ namespace ui
GET_SCREEN_RECT_ID, GET_SCREEN_RECT_ID,
SET_TITLEBAR_HEIGHT_ID, SET_TITLEBAR_HEIGHT_ID,
SET_WINDOW_LAYER_ID, SET_WINDOW_LAYER_ID,
UPDATE_PLEDGE_REQUEST_ID,
}; };
struct CreateWindowRequest struct CreateWindowRequest
@ -97,4 +98,16 @@ namespace ui
int window; int window;
Layer layer; Layer layer;
}; };
enum Pledge : i16
{
ExtendedLayers = 1,
};
struct UpdatePledgeRequest
{
static constexpr u8 ID = UPDATE_PLEDGE_REQUEST_ID;
i16 pledges;
};
} }

View File

@ -135,4 +135,11 @@ namespace ui
m_window_clear_queue.clear_data(); m_window_clear_queue.clear_data();
return !m_should_close; return !m_should_close;
} }
void App::pledge(i16 pledges)
{
ui::UpdatePledgeRequest request;
request.pledges = pledges;
client().send_async(request);
}
} }

View File

@ -11,6 +11,7 @@ set(SOURCES
Keyboard.cpp Keyboard.cpp
Keyboard.h Keyboard.h
Client.h Client.h
Client.cpp
Layer.cpp Layer.cpp
Layer.h Layer.h
) )

52
gui/wind/Client.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "Client.h"
#include <os/File.h>
Client::Client(OwnedPtr<os::IPC::ClientConnection>&& 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;
}

View File

@ -3,20 +3,19 @@
#include "Window.h" #include "Window.h"
#include <os/IPC.h> #include <os/IPC.h>
constexpr i16 HAS_NOT_YET_PLEDGED = -1;
constexpr i16 EMPTY_PLEDGE = 0;
struct Client struct Client
{ {
OwnedPtr<os::IPC::ClientConnection> conn; OwnedPtr<os::IPC::ClientConnection> conn;
Vector<Window*> windows; Vector<Window*> windows;
const bool privileged { false }; const bool privileged { false };
bool should_be_disconnected { false }; bool should_be_disconnected { false };
i16 pledges = 0;
Client(OwnedPtr<os::IPC::ClientConnection>&& client, bool priv) bool update_pledges(i16 pledges);
#ifdef CLIENT_IMPLEMENTATION bool check_pledge(i16 pledge);
: conn(move(client)), windows(), privileged(priv)
{ Client(OwnedPtr<os::IPC::ClientConnection>&& client, i16 pledges);
conn->set_message_handler(wind::handle_ipc_message, this);
}
#else
;
#endif
}; };

View File

@ -166,11 +166,9 @@ static Result<void> handle_set_window_layer_message(Client& client)
ui::SetWindowLayer request; ui::SetWindowLayer request;
if (!TRY(client.conn->read_message(request))) return {}; 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!"); if (!client.check_pledge(ui::Pledge::ExtendedLayers)) return {};
client.should_be_disconnected = true;
return {};
} }
CHECK_WINDOW_ID(request, "SetWindowLayer"); CHECK_WINDOW_ID(request, "SetWindowLayer");
@ -199,6 +197,16 @@ static Result<void> handle_set_window_layer_message(Client& client)
return {}; return {};
} }
static Result<void> 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 namespace wind
{ {
void handle_ipc_message(os::IPC::ClientConnection&, u8 id, void* c) 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::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_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::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; default: os::eprintln("wind: Invalid IPC message from client!"); return;
} }
} }

View File

@ -1,4 +1,3 @@
#define CLIENT_IMPLEMENTATION
#include "Client.h" #include "Client.h"
#include "Keyboard.h" #include "Keyboard.h"
#include "Layer.h" #include "Layer.h"
@ -138,7 +137,7 @@ Result<int> luna_main(int argc, char** argv)
auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client))); auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client)));
OwnedPtr<Client> c = TRY(adopt_owned_if_nonnull(new Client(move(connection), false))); OwnedPtr<Client> c = TRY(adopt_owned_if_nonnull(new Client(move(connection), EMPTY_PLEDGE)));
TRY(clients.try_append(move(c))); TRY(clients.try_append(move(c)));
} }
if (fds[3].revents & POLLIN) if (fds[3].revents & POLLIN)
@ -149,7 +148,7 @@ Result<int> luna_main(int argc, char** argv)
auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client))); auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client)));
OwnedPtr<Client> c = TRY(adopt_owned_if_nonnull(new Client(move(connection), true))); OwnedPtr<Client> c = TRY(adopt_owned_if_nonnull(new Client(move(connection), HAS_NOT_YET_PLEDGED)));
TRY(clients.try_append(move(c))); TRY(clients.try_append(move(c)));
} }
for (usize i = 0; i < clients.size(); i++) for (usize i = 0; i < clients.size(); i++)