Skip to content

Commit

Permalink
agent helper: support separate socket-activated service to run withou…
Browse files Browse the repository at this point in the history
…t SETUID

SETUID binaries are considered harmful, as te execution context is
under the control of unprivileged attackers.

Enhance the polkit pam agent helper with a new mode: when running
under systemd, add a socket-activated service that the helper will
run under, as root. The agent talks to this service via AF_UNIX
instead of spawning it, and STDIN/STDOUT are connected as before.
The helper can make use of PID FDs and SO_PEERCRED to reliably
identify the caller. In order to do this, a third version of the
auth D-Bus method is added, that also takes a subject, built using
the PID FD.
If the AF_UNIX socket is not present, the agent will fork the
helper as before, with no changes.

Fixes polkit-org#169
  • Loading branch information
bluca committed Sep 16, 2024
1 parent d68a3b4 commit 8567dbb
Show file tree
Hide file tree
Showing 14 changed files with 474 additions and 36 deletions.
13 changes: 13 additions & 0 deletions data/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ configure_file(
install_dir: systemdsystemunitdir,
)

configure_file(
input: '[email protected]',
output: '@BASENAME@',
configuration: service_conf,
install: true,
install_dir: systemdsystemunitdir,
)

install_data(
'polkit-agent-helper.socket',
install_dir: systemdsystemunitdir,
)

configure_file(
input: 'polkit.conf.in',
output: '@BASENAME@',
Expand Down
11 changes: 11 additions & 0 deletions data/polkit-agent-helper.socket
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=Authorization Manager Agent Helper
Documentation=man:polkit(8)

[Socket]
Accept=yes
RemoveOnStop=yes
ListenStream=/run/polkit/agent-helper.socket

[Install]
WantedBy=sockets.target
34 changes: 34 additions & 0 deletions data/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[Unit]
Description=Authorization Manager Agent Helper
Documentation=man:polkit(8)

[Service]
Type=oneshot
DeviceAllow=/dev/null rw
DevicePolicy=strict
ExecStart=@libprivdir@/polkit-agent-helper-1 --socket-activated
StandardInput=socket
StandardOutput=socket
LimitMEMLOCK=0
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateNetwork=yes
PrivateTmp=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectKernelTunables=yes
ProtectSystem=strict
ProtectClock=yes
ProtectHostname=yes
RemoveIPC=yes
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
UMask=0077
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ Structure <link linkend="eggdbus-struct-TemporaryAuthorization">TemporaryAuth
IN <link linkend="eggdbus-struct-Identity">Identity</link> identity)
<link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse2">AuthenticationAgentResponse2</link> (IN uint32 uid, IN String cookie,
IN <link linkend="eggdbus-struct-Identity">Identity</link> identity)
<link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse3">AuthenticationAgentResponse3</link> (IN String cookie,
IN <link linkend="eggdbus-struct-Identity">Identity</link> identity,
IN <link linkend="eggdbus-struct-Subject">Subject</link> subject)
<link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.EnumerateTemporaryAuthorizations">EnumerateTemporaryAuthorizations</link> (IN <link linkend="eggdbus-struct-Subject">Subject</link> subject,
OUT Array&lt;<link linkend="eggdbus-struct-TemporaryAuthorization">TemporaryAuthorization</link>&gt; temporary_authorizations)
<link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RevokeTemporaryAuthorizations">RevokeTemporaryAuthorizations</link> (IN <link linkend="eggdbus-struct-Subject">Subject</link> subject)
Expand Down Expand Up @@ -316,7 +319,7 @@ Details about the subject. Depending of the value of <parameter>subject_kind</pa
}
</programlisting>
<para>
<para>This struct describes identities such as UNIX users and UNIX groups. It is typically used to check if a given process is authorized for an action.</para><para>The following kinds of identities are known:</para> <formalpara><title>Unix User</title><para><literal>identity_kind</literal> should be set to <literal>unix-user</literal> with key <literal>uid</literal> (of type <literal>uint32</literal>).</para></formalpara> <formalpara><title>Unix Group</title><para><literal>identity_kind</literal> should be set to <literal>unix-group</literal> with key <literal>gid</literal> (of type <literal>uint32</literal>).</para></formalpara>
<para>This struct describes identities such as UNIX users and UNIX groups. It is typically used to check if a given process is authorized for an action.</para><para>The following kinds of identities are known:</para> <formalpara><title>Unix User</title><para><literal>identity_kind</literal> should be set to <literal>unix-user</literal> with key <literal>uid</literal> (of type <literal>uint32</literal>).</para></formalpara> <formalpara><title>Unix Group</title><para><literal>identity_kind</literal> should be set to <literal>unix-group</literal> with key <literal>gid</literal> (of type <literal>uint32</literal>).</para></formalpara>
</para>
<variablelist role="struct">
<varlistentry>
Expand Down Expand Up @@ -853,6 +856,47 @@ A <link linkend="eggdbus-struct-Identity">Identity</link> struct describing what
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2 role="function" id="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse3">
<title>AuthenticationAgentResponse3 ()</title>
<programlisting>
AuthenticationAgentResponse3 (IN String cookie,
IN <link linkend="eggdbus-struct-Identity">Identity</link> identity,
IN <link linkend="eggdbus-struct-Subject">Subject</link> subject)
</programlisting>
<para>
Method for authentication agents to invoke on successful
authentication, intended only for use by a privileged helper process
running via socket activation. This method will fail unless a sufficiently privileged
caller invokes it. In contract to other methods this takes a subject as input, which
allows reliably tracking the requester via PID FD.
</para>
<variablelist role="params">
<varlistentry>
<term><literal>IN String <parameter>cookie</parameter></literal>:</term>
<listitem>
<para>
The cookie identifying the authentication request that was passed to the authentication agent.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>IN <link linkend="eggdbus-struct-Identity">Identity</link> <parameter>identity</parameter></literal>:</term>
<listitem>
<para>
A <link linkend="eggdbus-struct-Identity">Identity</link> struct describing what identity was authenticated.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>IN <link linkend="eggdbus-struct-Subject">Subject</link> <parameter>subject</parameter></literal>:</term>
<listitem>
<para>
A <link linkend="eggdbus-struct-Subject">Subject</link> struct describing what entity requested the authentication.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2 role="function" id="eggdbus-method-org.freedesktop.PolicyKit1.Authority.EnumerateTemporaryAuthorizations">
Expand Down
2 changes: 2 additions & 0 deletions docs/polkit/polkit-1-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ polkit_authority_unregister_authentication_agent_sync
polkit_authority_authentication_agent_response
polkit_authority_authentication_agent_response_finish
polkit_authority_authentication_agent_response_sync
polkit_authority_authentication_agent_response_with_subject
polkit_authority_authentication_agent_response_with_subject_sync
polkit_authority_enumerate_temporary_authorizations
polkit_authority_enumerate_temporary_authorizations_finish
polkit_authority_enumerate_temporary_authorizations_sync
Expand Down
110 changes: 110 additions & 0 deletions src/polkit/polkitauthority.c
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,69 @@ polkit_authority_unregister_authentication_agent_sync (PolkitAuthority *auth

/* ---------------------------------------------------------------------------------------------------- */

/**
* polkit_authority_authentication_agent_response:
* @authority: A #PolkitAuthority.
* @cookie: The cookie passed to the authentication agent from the authority.
* @identity: The identity that was authenticated.
* @subject: The subject that requested the authentication.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @callback: A #GAsyncReadyCallback to call when the request is satisfied.
* @user_data: The data to pass to @callback.
*
* Asynchronously provide response that @identity successfully authenticated
* for the authentication request identified by @cookie as requested by @subject.
*
* This function is only used by the socket-activated agent helper, running as uiid
* 0, and will fail otherwise. The requesting process is identified via @subject
* which will contain a PID FD identifying the process.
*
* When the operation is finished, @callback will be invoked in the
* <link linkend="g-main-context-push-thread-default">thread-default
* main loop</link> of the thread you are calling this method
* from. You can then call
* polkit_authority_authentication_agent_response_finish() to get the
* result of the operation.
**/
void
polkit_authority_authentication_agent_response_with_subject (PolkitAuthority *authority,
const gchar *cookie,
PolkitIdentity *identity,
PolkitSubject *subject,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
/* Unlike the polkit_authority_authentication_agent_response variant,
* this one is called from a socket-activated service, rather than a
* setuid helper invoked directly by the authenticating process.
*/
uid_t uid = getuid ();

g_return_if_fail (POLKIT_IS_AUTHORITY (authority));
g_return_if_fail (cookie != NULL);
g_return_if_fail (POLKIT_IS_IDENTITY (identity));
g_return_if_fail (POLKIT_IS_SUBJECT (subject));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));

g_dbus_proxy_call (authority->proxy,
"AuthenticationAgentResponse3",
g_variant_new ("(s@(sa{sv})@(sa{sv}))",
cookie,
polkit_identity_to_gvariant (identity), /* Floating value */
polkit_subject_to_gvariant (subject)), /* Floating value */
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
generic_async_cb,
g_simple_async_result_new (G_OBJECT (authority),
callback,
user_data,
polkit_authority_authentication_agent_response));
}

/* ---------------------------------------------------------------------------------------------------- */

/**
* polkit_authority_authentication_agent_response:
* @authority: A #PolkitAuthority.
Expand Down Expand Up @@ -1630,6 +1693,53 @@ polkit_authority_authentication_agent_response_sync (PolkitAuthority *author
return ret;
}


/**
* polkit_authority_authentication_agent_response_with_subject_sync:
* @authority: A #PolkitAuthority.
* @cookie: The cookie passed to the authentication agent from the authority.
* @identity: The identity that was authenticated.
* @subject: The subject that requested the authentication.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: (allow-none): Return location for error or %NULL.
*
* Provide response that @identity successfully authenticated for the
* authentication request identified by @cookie. See polkit_authority_authentication_agent_response_with_subject()
* for limitations on who is allowed is to call this method.
*
* The calling thread is blocked until a reply is received. See
* polkit_authority_authentication_agent_response_with_subject() for the
* asynchronous version.
*
* Returns: %TRUE if @authority acknowledged the call, %FALSE if @error is set.
**/
gboolean
polkit_authority_authentication_agent_response_with_subject_sync (PolkitAuthority *authority,
const gchar *cookie,
PolkitIdentity *identity,
PolkitSubject *subject,
GCancellable *cancellable,
GError **error)
{
gboolean ret;
CallSyncData *data;

g_return_val_if_fail (POLKIT_IS_AUTHORITY (authority), FALSE);
g_return_val_if_fail (cookie != NULL, FALSE);
g_return_val_if_fail (POLKIT_IS_IDENTITY (identity), FALSE);
g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), FALSE);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

data = call_sync_new ();
polkit_authority_authentication_agent_response_with_subject (authority, cookie, identity, subject, cancellable, call_sync_cb, data);
call_sync_block (data);
ret = polkit_authority_authentication_agent_response_finish (authority, data->res, error);
call_sync_free (data);

return ret;
}

/* ---------------------------------------------------------------------------------------------------- */

/**
Expand Down
15 changes: 15 additions & 0 deletions src/polkit/polkitauthority.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ gboolean polkit_authority_authentication_agent_response_sync (
GCancellable *cancellable,
GError **error);

gboolean polkit_authority_authentication_agent_response_with_subject_sync (PolkitAuthority *authority,
const gchar *cookie,
PolkitIdentity *identity,
PolkitSubject *subject,
GCancellable *cancellable,
GError **error);

GList *polkit_authority_enumerate_temporary_authorizations_sync (PolkitAuthority *authority,
PolkitSubject *subject,
GCancellable *cancellable,
Expand Down Expand Up @@ -186,6 +193,14 @@ void polkit_authority_authentication_agent_response (Polki
GAsyncReadyCallback callback,
gpointer user_data);

void polkit_authority_authentication_agent_response_with_subject (PolkitAuthority *authority,
const gchar *cookie,
PolkitIdentity *identity,
PolkitSubject *subject,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);

gboolean polkit_authority_authentication_agent_response_finish (PolkitAuthority *authority,
GAsyncResult *res,
GError **error);
Expand Down
2 changes: 1 addition & 1 deletion src/polkitagent/polkitagenthelper-bsdauth.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ main (int argc, char *argv[])
/* now send a D-Bus message to the polkit daemon that
* includes a) the cookie; and b) the user we authenticated
*/
if (!send_dbus_message (cookie, user_to_auth))
if (!send_dbus_message (cookie, user_to_auth, -1, -1))
{
#ifdef PAH_DEBUG
fprintf (stderr, "polkit-agent-helper-1: error sending D-Bus message to polkit daemon\n");
Expand Down
Loading

0 comments on commit 8567dbb

Please sign in to comment.