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
Allow D-Bus methods to auth. for more than one polkit action #26365
Conversation
An -rc1 tag has been created and a release is being prepared, so please note that PRs introducing new features and APIs will be held back until the new version has been released. |
6f03519
to
bcf3e64
Compare
This comment was marked as outdated.
This comment was marked as outdated.
src/shared/bus-polkit.c
Outdated
@@ -379,6 +473,20 @@ int bus_verify_polkit_async( | |||
if (r < 0) | |||
return r; | |||
|
|||
if (!qs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this condition necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is. On the first call of this function (for given call
), qs
will be NULL
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, here qs
is always NULL
, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. When a dbus method needs to auth. for a polkit action, it calls bus_verify_polkit_async()
. The function creates an AsyncPolkitQueries
instance (and stores it into registry
), an AsyncPolkitQuery
instance, and issues an async call to polkit. The dbus method then returns immediately after returning from bus_verify_polkit_async()
. When the async call finishes, async_polkit_callback()
gets called, which stores the reply in its associated AsyncPolkitQuery
object and reschedules the same bus message for processing. This time, when bus_verify_polkit_async()
is called, it finds that a query for this call
+ action
combination is already present in registry
, hence it just processes the reply and returns. If the method then needs to auth. for another action, it calls bus_verify_polkit_async()
again. This time, no existing query is found in the registry
(it's a different action than previously), but the AsyncPolkitQueries
is (as we're still processing the same bus message), hence qs
is set. The function then proceeds with creating another query (so qs
contains two items now, each for a different action) and issues another async call to polkit. The dbus method again returns and is later rescheduled by async_polkit_callback()
. And so on...
I hope this is at least a bit understandable...
(Btw, if this sounds complicated, it's because it is :-) But most of the complexity is due to the async. nature of this and has already been there before.)
|
||
r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0); | ||
if (r < 0) { | ||
async_polkit_query_free(q); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this is dropped?? q
seems to be leaked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not leaked. At this point, q
is already managed by qs
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, then, I'd like to move LIST_PREPEND in the above after the bus call.
src/shared/bus-polkit.c
Outdated
if (!qs) | ||
return NULL; | ||
|
||
LIST_FOREACH(item, i, qs->items) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about to store query into a hashmap by the action?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not worth it. In most cases there'll be only one item in the list.
bcf3e64
to
4fad040
Compare
4fad040
to
225fb0e
Compare
225fb0e
to
72abb01
Compare
I've added a detailed (and hopefully understandable) explanation how the polkit auth. works. I hope that makes the change easier to understand. |
72abb01
to
63ef492
Compare
hmm, can you split out the first three commits in a PR of its own? we should be able to merge those as generally useful cleanups independently of the rest, once they pass CI. |
hmm, what I don't get about this, wouldn't it suffice to add a new strv field to AsyncPolkitQuery that lists all actions that have already been validated in the current method handling? Then, when we can just check against those whenever we are called, and only do requests for the stuff we haven't validated yet. |
Will do. |
Does "I haven't thought of that" count as an answer? .-) |
There are no user facing stuff, so actually it's fine to get in a bit later for 254 if you have time to get the review comments sorted this week or next week @dtardon |
f4ba6ac
to
03830fa
Compare
Btw, #28381 is my attempt to create a test for polkit authentication. Unfortunately, it's not ready yet: the script runs just fine locally, but it always fails (at different places) when I run it as a test. And I have no idea why... |
This is a preparation for later commits.
... and store just the result.
03830fa
to
969d807
Compare
In systemd#20155, verify_shutdown_creds() needs to authenticate for both org.freedesktop.login1.hibernate-multiple-sessions and org.freedesktop.login1.hibernate-ignore-inhibit . Previously, the second authentication attempt would fail with -ESTALE. Fixes systemd#20155.
969d807
to
b1ebc20
Compare
@@ -214,7 +220,11 @@ static AsyncPolkitQuery *async_polkit_query_free(AsyncPolkitQuery *q) { | |||
|
|||
sd_event_source_disable_unref(q->defer_event_source); | |||
|
|||
async_polkit_query_action_free(q->authorized_action); | |||
while ((a = q->authorized_actions)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LIST_POP()
…failure As reported by [1] [2], the return code of systemctl command between systemd 253 and 254 has changed when the polkit authentication is refused: /bin/systemctl restart systemd-timesyncd.service The return code changed from 1 to 4. The Polkit test case "TestPolkitSystemd" expected 1 as return code [3]. The service log is not the same either: systemd v253: Failed to restart systemd-timesyncd.service: Interactive authentication required. systemd v254: Failed to restart systemd-timesyncd.service: Access denied git bisect report this commit: systemd/systemd@959301c From the PR (to get more context): systemd/systemd#26365 Note: systemd doesn't recommend using systemctl exit code to check unit states: "The mapping of LSB service states to systemd unit states is imperfect, so it is better to not rely on those return values but to look for specific unit states and substates instead." Since we only want to check if the command failed, update our test to check if systemctl returned a non zero code whatever the reason of the failure. Thanks to Yann E. MORIN for the brainstorming! Fixes: https://gitlab.com/buildroot.org/buildroot/-/jobs/4768561464 (TestPolkitSystemd) [1] http://lists.busybox.net/pipermail/buildroot/2023-August/671900.html [2] https://lists.freedesktop.org/archives/systemd-devel/2023-August/049362.html [3] https://git.buildroot.net/buildroot/tree/support/testing/tests/package/test_polkit.py?h=2023.08-rc1#n45 [4] https://github.com/systemd/systemd/blob/v254/man/systemctl.xml#L2612 Signed-off-by: Romain Naour <romain.naour@smile.fr> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
An error reply from polkit is a valid case and should not be propagated as failure of async_polkit_callback(). It should only be saved here. It'll be returned by bus_verify_polkit_async() later, when it's called for the same method again. Follow-up for systemd#26365.
An error reply from polkit is a valid case and should not be propagated as failure of async_polkit_callback(). It should only be saved here. It'll be returned by bus_verify_polkit_async() later, when it's called for the same method again. Follow-up for #26365.
…failure As reported by [1] [2], the return code of systemctl command between systemd 253 and 254 has changed when the polkit authentication is refused: /bin/systemctl restart systemd-timesyncd.service The return code changed from 1 to 4. The Polkit test case "TestPolkitSystemd" expected 1 as return code [3]. The service log is not the same either: systemd v253: Failed to restart systemd-timesyncd.service: Interactive authentication required. systemd v254: Failed to restart systemd-timesyncd.service: Access denied git bisect report this commit: systemd/systemd@959301c From the PR (to get more context): systemd/systemd#26365 Note: systemd doesn't recommend using systemctl exit code to check unit states: "The mapping of LSB service states to systemd unit states is imperfect, so it is better to not rely on those return values but to look for specific unit states and substates instead." Since we only want to check if the command failed, update our test to check if systemctl returned a non zero code whatever the reason of the failure. Thanks to Yann E. MORIN for the brainstorming! Fixes: https://gitlab.com/buildroot.org/buildroot/-/jobs/4768561464 (TestPolkitSystemd) [1] http://lists.busybox.net/pipermail/buildroot/2023-August/671900.html [2] https://lists.freedesktop.org/archives/systemd-devel/2023-August/049362.html [3] https://git.buildroot.net/buildroot/tree/support/testing/tests/package/test_polkit.py?h=2023.08-rc1#n45 [4] https://github.com/systemd/systemd/blob/v254/man/systemctl.xml#L2612 Signed-off-by: Romain Naour <romain.naour@smile.fr> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
An error reply from polkit is a valid case and should not be propagated as failure of async_polkit_callback(). It should only be saved here. It'll be returned by bus_verify_polkit_async() later, when it's called for the same method again. Follow-up for systemd#26365. (cherry picked from commit 45b1c01)
The current code handling async. polkit authentication allows a D-Bus method to auth. for at most one action. If the same method tries to auth. for another action, it'll end with
-ESTALE
. That's a problem forverify_shutdown_creds()
, which may need to authenticate for bothorg.freedesktop.login1.hibernate-multiple-sessions
andorg.freedesktop.login1.hibernate-ignore-inhibit
. This PR extends the handling of async. polkit requests to allow auth. for multiple actions. Unfortunately, it increases complexity of already quite complex code (esp. wrt. memory management)...Fixes #20155