[Spice-devel] [PATCH spice-gtk 4/5] Add a suid root helper to open usb device nodes

Hans de Goede hdegoede at redhat.com
Wed Nov 16 09:39:58 PST 2011


Hi,

First of all, since I think I forgot to say so yesterday:
Many thanks for the review!

On 11/16/2011 01:53 PM, Marc-André Lureau wrote:
> Hi
>

<snip>

>>>> +        priv->result = result;
>>>> +        priv->acl_helper = spice_usb_acl_helper_new();
>>>
>>> They should be closed&    disposed in dispose imho.
>>
>> The close, closes stdin of the helper, at which point it will restore
>> the acl to its original state and then exit. Which I would rather see done
>> sooner then later.
> []
>> So the lifetime of the helper should be either one of the connected time of
>> the
>> channel, or just long enough for the channel code to open the device. Since
>> there
>> is no need for / use in keeping the helper around after the channel code has
>> opened the device node I've choosen for the latter.
>
> I understand you don't want to delay it until dispose. I was thinking
> in term of regular object lifecycle, if it gets dispose (even in a
> weird state), it shouldn't leak imho and should restore whatever state
> it changed if sensible.

Agreed, and it will. In the unlike scenario that the session releases its
last reference to the channel while it is waiting for the acl_helper,
then it won't get finalized until the helper has completed since priv->result
holds a referenced to self, and priv->result won't get unrefed (which
will cause the self ref to be unreffed once the completion of priv->result
has been done in idle) until the acl_helper has completed. This means that either:
1) There are no active references at dispose time
2) There are active refs but they get immediately unreffed by disconnect
3) There are active and we're waiting for the acl_helper, in the case the
finalize won't happen until the acl_helper_open has completed, at which
point all refs we hold will have been unreffed by the acl open complete
callback.

>
>>>
>>>> +        spice_usb_acl_helper_open_acl(priv->acl_helper,
>>>> +                                      g_usb_device_get_bus(device),
>>>> +                                      g_usb_device_get_address(device),
>>>> +                                      cancellable,
>>>> +
>>>>   spice_usbredir_channel_open_acl_cb,
>>>> +                                      channel);
>>>
>>> Since the SpiceUsbAclHelper keep running when it's unref, we should
>>> give away a reference to the channel.  And probably close&    dispose on
>>> channel dispose. See below
>>>
>>
>> I'm afraid don't understand / completely follow what you're trying to say
>> here...
>
> I am trying to say that in term of object lifecycle (sorry, again) we
> have a problem, since you can unref the SpiceUsbAclHelper from the
> channel, but the helper will keep running and eventually reach the cb
> with a channel object that it doesn't own. So it might run into
> reference issues. Instead, we should give away a ref (wrong imho) or
> have a real weak-reference that get notified when channel object is
> disposed so we stop the helper from calling it back.

This is not an issue, because of the same reasoning as above.

>
>>>> +#if USE_POLKIT
>>>> +    /*
>>>> +     * If we're still waiting for the acl helper cancel it and don't
>>>> clear
>>>> +     * priv->device and context, keeping this channel "busy" until
>>>> +     * spice_usbredir_channel_open_acl_cb() has run from the main loop,
>>>> +     * avoiding a new connect happening before the old connect has
>>>> finished.
>>>> +     */
>>>
>>> If it's called from finalize() I don't see how you could keep the
>>> channel "busy".
>>
>> It cannot be called from finalize() while the acl_helper is still active,
>> since the async result holds a reference to its source object, and we don't
>> unref the result until the acl_open completes at which point acl_helper will
>> be unset.
>
> Can you add this comment or reformulate it, it's easy to get it wrong :)

I've reworked the usb-channel code to keep track of its state in a state
variable and decide what to do in disconnect based on the state. This makes
the code much clearer. I've also added a comment explaining why just doing
a disconnect on dispose, and not having any finalize at all (see new version
of the patchset) is enough to ensure we always properly clean up after
ourselves.

>
>
>>>> +    if (priv->acl_helper) {
>>>> +        spice_usb_acl_helper_close_acl(priv->acl_helper);
>>>> +    } else
>>>
>>> Do we need a else?
>>>
>>
>> Yes, otherwise we could get:
>> channel_open_device 1 ->  in progress
>> channel_close_device()
>>   calls spice_usb_acl_helper_close_acl
>>   cancels the pending acl open, will complete open in idle!
>> channel_open_device 2
>>   sets priv->device to new device
>> acl_open called from channel_open_device 1 completes
>>   complete callback clears priv->device since there is an err (it was
>> cancelled)
>>
>> But now it is clearing the new device from the 2nd open! Hence the else,
>> which results in keeping the channel in the open / busy state until the
>> acl_open complete callback runs from idle.
>
> hmm ok
>
>> I've discussed this with Kay in the sense of: "Kay, can't we let udev
>> do the acl mangling for us like it does for normal devices too" and
>> the answer to that was no. Using an other group for usb devices
>> and making the helper sgid to this group won't work since changing
>> acl's can only be done by the file owner and root. We could change
>> the default owner of the usb files to a special user and have the helper
>> be suid this user. I'll discuss this with Kay tomorrow.
>
> That's what I had in mind. I don't think that should prevent us from
> merging your patches though.

I've discussed this with Kay, but both of us had a rather high reply latency,
so there is no conclusion yet, to be continued.

Regards,

Hans


p.s.

New revision of the patchset should land in your mailbox in a couple of
minutes


More information about the Spice-devel mailing list