Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for security-context-v1 #1817

Merged
merged 1 commit into from
May 29, 2024

Conversation

nesteroff
Copy link
Contributor

@nesteroff nesteroff commented May 14, 2024

This adds support for the security-context-v1 protocol. It is used by sandbox engines to restrict the features that sandboxed connections can use. For example, it is currently supported by Flatpak.

The implementation is based on the Sway code but adapted to Labwc. The sandbox_engine and sandbox_app_id parameters are added to window rules in order to be able to apply different rules for sandboxed clients.

The easiest way to test it is probably to take a recent version of Flatpak. Use it to run a Wayland application (for example, Firefox) with WAYLAND_DEBUG enabled and check for wp_security_context in the logs.

@Consolatis
Copy link
Member

First of all, thanks for the PR.

What is the purpose of adding support for the sandbox manager engine / app_id to the window rules?

I am not that much in favor of hardcoding a list of "privileged" protocols for any sandboxed client, it seems cleaner to allow the user to define the protocols instead based on the sandbox engine name and potentially the sandbox engine app_id.

@Consolatis Consolatis added this to the 0.7.3 milestone May 14, 2024
@nesteroff
Copy link
Contributor Author

What is the purpose of adding support for the sandbox manager engine / app_id to the window rules?

It can be used to help users visually identify applications running in sandboxes. One use case is when multiple instances of a single application are running under different security policies. For example, a user might have two browsers running: one for untrusted web apps, which is isolated in a sandbox, and another running normally. In this case, the user can configure different window styles with different colors to quickly identify which is which.

I am not that much in favor of hardcoding a list of "privileged" protocols for any sandboxed client, it seems cleaner to allow the user to define the protocols instead based on the sandbox engine name and potentially the sandbox engine app_id.

Sure, it definitely needs to be more flexible. I just thought we could start with a simple implementation, where there is a reasonable set of protocols blocked for sandboxed clients by default. Later on, we could add the ability to whitelist or blacklist other protocols.

I guess it could be something like this:

<sandboxRules>
    <sandboxRule app_id="org.mozilla.firefox" engine="org.flatpak">
        <protocol name="output_power_manager_v1" restrict="no" />
    </sandboxRule>
</sandboxRules>

@Consolatis
Copy link
Member

Consolatis commented May 14, 2024

I am not that much in favor of hardcoding a list of "privileged" protocols for any sandboxed client, it seems cleaner to allow the user to define the protocols instead based on the sandbox engine name and potentially the sandbox engine app_id.

Sure, it definitely needs to be more flexible. I just thought we could start with a simple implementation, where there is a reasonable set of protocols blocked for sandboxed clients by default. Later on, we could add the ability to whitelist or blacklist other protocols.

If we make the hardcoded list depend on the sandbox engine being org.flatpak for now I would feel more comfortable with that approach.

I guess it could be something like this:

Just for reference, some earlier work (without the security context protocol but using different wayland sockets instead that can be bind-mounted into filesystem namespaces):

@nesteroff
Copy link
Contributor Author

If we make the hardcoded list depend on the sandbox engine being org.flatpak for now I would feel more comfortable with that approach.

Well, it will result in more hardcoding in the sources. What if I just remove all hardcoded protocols and leave only security_context_manager_v1 for now?

Just for reference, some earlier work (without the security context protocol but using different wayland sockets instead that can be bind-mounted into filesystem namespaces):

That's interesting. Thanks for sharing. I didn't know you had already thought about it. Are you still going to work on that PR, or would you like me to use it as a reference to add settings to rc.xml?

@Consolatis
Copy link
Member

Well, it will result in more hardcoding in the sources. What if I just remove all hardcoded protocols and leave only security_context_manager_v1 for now?

I would be fine with having a minimal PR first that only adds the protocol support and blocks the security context protocol itself.
Although I don't know if flatpak or other sandbox engines have expectations like "that protocol is supported so these X protocols are blocked" and thus this would actually result in less security (by sandbox engines relying on that assumption instead of spawning a nested compositor for example) rather than enhance it.

In the longer term I think we could add some rule framework and then have hardcoded defaults (potentially per sandbox engine) that are applied when there is no user configuration for the given sandbox engine.

That's interesting. Thanks for sharing. I didn't know you had already thought about it. Are you still going to work on that PR, or would you like me to use it as a reference to add settings to rc.xml?

The later versions of that PR are still somewhere on a local branch but I think the security context protocol is preferable to the separate socket approach, combined with WAYLAND_SOCKET=some_inherited_fd that should handle most use-cases.

@nesteroff
Copy link
Contributor Author

I would be fine with having a minimal PR first that only adds the protocol support and blocks the security context protocol itself. Although I don't know if flatpak or other sandbox engines have expectations like "that protocol is supported so these X protocols are blocked" and thus this would actually result in less security (by sandbox engines relying on that assumption instead of spawning a nested compositor for example) rather than enhance it.

Ok, sounds good. I've updated the PR with a minimal implementation. Hopefully, sandbox engines will not make any assumptions, since there doesn't seem to be any official list of protocols that the compositor must block for clients with a security context attached.

In the longer term I think we could add some rule framework and then have hardcoded defaults (potentially per sandbox engine) that are applied when there is no user configuration for the given sandbox engine.>

Yep, it would be nice to follow the fail-safe defaults principle, where everything that can potentially be considered insecure is blocked by default for sandboxed clients, and users manually allow permissions when needed.

Comment on lines 22 to 25
const struct wlr_security_context_v1_state *security_context =
wlr_security_context_manager_v1_lookup_client(
view->server->security_context_manager_v1, client);
return security_context;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could just be

return wlr_security_context_manager_v1_lookup_client(
	view->server->security_context_manager_v1, client);

@@ -29,6 +44,18 @@ matches_criteria(struct window_rule *rule, struct view *view)
return false;
}
}
if (rule->sandbox_engine) {
if (!security_context || !security_context->sandbox_engine
|| !match_glob(rule->sandbox_engine, security_context->sandbox_engine)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code style nit: double indent for multi line ifs. Same in the next condition.

Comment on lines 188 to 193
} else if (!strcmp(nodename, "sandbox_engine")) {
free(current_window_rule->sandbox_engine);
current_window_rule->sandbox_engine = xstrdup(content);
} else if (!strcmp(nodename, "sandbox_app_id")) {
free(current_window_rule->sandbox_app_id);
current_window_rule->sandbox_app_id = xstrdup(content);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we usually use the sandboxEngine format for user facing settings. Same for sandboxAppId.

@johanmalm johanmalm marked this pull request as draft May 19, 2024 20:56
@nesteroff nesteroff force-pushed the security-context branch 2 times, most recently from e6f20c4 to ac76230 Compare May 27, 2024 11:15
@nesteroff nesteroff marked this pull request as ready for review May 27, 2024 11:22
@nesteroff
Copy link
Contributor Author

Sorry for the delay. I was traveling last week. The code has been updated and rebased. Please have a look.

src/view.c Outdated
@@ -67,6 +81,8 @@ view_matches_query(struct view *view, struct view_query *query)
{
bool match = true;
bool empty = true;
const struct wlr_security_context_v1_state *security_context =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't analysed this, but suspect view_matches_query() is called a lot, thus making anything within it is therefore an expensive operation.

Unless I'm wrong in that, would it make sense to declare + initialize it to NULL at the top; and then set it to security_context_from_view() iff match && (query->sandbox_engine || query->sandbox_app_id)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I reduced the scope of the security_context variable to be used only when needed.

@johanmalm
Copy link
Collaborator

LGTM
Keen to understand what the next PR might look like - but not a prerequisite to merging.

@nesteroff
Copy link
Contributor Author

LGTM Keen to understand what the next PR might look like - but not a prerequisite to merging.

Thanks. I think the next step is to add the ability to configure which protocols are available for sandboxed clients, similar to what @Consolatis shared in this thread. It probably shouldn't be too hard to adapt it to the secure context.

@johanmalm johanmalm merged commit 65f7499 into labwc:master May 29, 2024
5 checks passed
@johanmalm
Copy link
Collaborator

Thanks. Excellent work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants