RFC: adding fd-passing to win32

Marc-André Lureau marcandre.lureau at gmail.com
Fri Aug 5 07:35:54 UTC 2022


Hi

On Thu, Aug 4, 2022 at 11:36 PM Simon McVittie <smcv at collabora.com> wrote:

> On Wed, 03 Aug 2022 at 14:54:21 +0400, Marc-André Lureau wrote:
> > The array elements have
> > the handle type & value or details for SOCKET. The body 'H' arguments
> index the
> > array, similar to 'h' FDs values.
>
> Is there a reason why the wire protocol can't use the same 'h' type as
> on Unix? In the wire protocol, the 'h' type is just a special sort of
> integer, with the conventional semantics being that it is an index into an
> array of out-of-band file descriptors. Can the Windows equivalent be making
> it an index into an array of HANDLEs?
>

As you probably know, HANDLEs are not FD. And Windows has the 2 types, and
functions to map to/from the 2 (_get_osfhandle/_open_osfhandle).

With the addition of AF_UNIX socket support, Windows developers have shown
interest in adding more features over time (
https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/#unsupportedunavailable),
including SCM_RIGHTS/fdpass.

If some day, Windows has SCM_RIGHTS, we should enable that code too. For
those reasons, I think we should add a new type. If 'H' is not a good
character, please advise.


> This would work very well for GDBus, which literally represents the 'h'
> type as an integer index into the GUnixFdList, but might be a bit weird
> in libdbus, which transparently replaces the integer index with the actual
> file descriptor (which of course will usually be numerically unequal to
> either the index, or the fd in the sender) while iterating a received
> message's arguments, or transparently replaces a fd with an index into
> the array of fds to be sent while building a new message to be sent.
> HANDLEs are not the same size as int, so the ABI for dealing with handles
> would be different on Unix and Windows.
>

I handled that in my dev branch. I introduced a new type to wrap HANDLE or
SOCKET (or future handle kinds as needed):

/*
 * Handles which are not yet supported:
 * - Change notification: FindCloseChangeNotification
 * - Event log: CloseEventLog
 * - Find file: FindClose
 * - Update resource: EndUpdateResource
 */

typedef struct DBusWinHandle DBusWinHandle;

struct DBusWinHandle {
  int type;
  union {
    SOCKET socket;
    HANDLE handle;
  } u;
};



> I can see why the authors of fd-passing in libdbus did it this way,
> but with hindsight, GDBus' approach is probably better.
>

may be :) in my glib/gio wip branch, I re-use the fdlist (mapping HANDLEs
to FD). The problem with that approach is that the client looses the HANDLE
type information, which may be hard to get back (there are "bad" &
undocumented windows API to do that). I plan to change that, to introduce a
HANDLE list & API instead.



> If the Windows HANDLEs or SOCKETs have to be sent in-band as ordinary
> bytes in the message stream, rather than out-of-band as a special
> kernel-mediated capability (which seems odd to me, but I'm not a
> Windows expert), then they should probably be in a new header field of
>

yes, you have to use DuplicateHandle/wsaduplicatesocket and send the handle
details to the target, via ipc.


> an appropriate type (perhaps 'at' if a bare 64-bit integer is enough,
> or 'a(t...)' if you need a 64-bit integer plus metadata, or something
> along those lines).
>
> Something like this (in GVariant-ish pseudocode):
>
> header = (
>     byte endianness,
>     byte message type,
>     byte flags,
>     byte major_version,
>     uint32 body_length,
>     uint32 serial,
>     @a(yv) {
>         PATH: <'/foo'>,
>         INTERFACE: <'com.example.ArbitraryCodeExecution'>,
>         MEMBER: <'ExecCommand'>,
>         ...,
>         WINDOWS_HANDLES: @a(t...) [                  # a new header field
>             (0x12345678, 'this one is stdin', ...),
>             (0x87654321, 'this one is stdout', ...),
>             (0x12121212, 'this one is stderr', ...),
>         ],
>     }
> )
>
> # 0-7 bytes of padding here, to reach next 8-byte boundary
>
> body = (
>     bytestring b'dir c:\',
>     handle 0,  # stdin is the 0'th item in WINDOWS_HANDLES, i.e. 0x12345678
>     handle 1,  # stdout is the 1st item
>     handle 2,  # stderr is the 2nd item
> )   # for a total of body_length bytes
>
> so that where Unix would have the number of out-of-band fds in the
> existing UNIX_FDS header field, Windows would instead have the in-band
> HANDLEs in the WINDOWS_HANDLES header field.
>


Yes, that's an idea I discussed with Thiago:
> 2) if the 'handle array' is itself embedded in the header fields, the
header content will need to be updated for each receiver when broadcasting.
> The second option might not be so bad after all, but my original design
kept the original message (header+body) untouched.



> > It seems the D-Bus protocol was designed so that the message size can be
> > computed from the header alone, with header + body + fields array size.
> The
> > reference implementation relies on that
> (_dbus_header_have_message_untrusted
> > for ex).
>
> Yes, the framing layer of the wire protocol is intended to make it possible
> to know how long the whole message is going to be by reading its first 16
> bytes. This should remain true.
>

Ok

-- 
Marc-André Lureau
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/dbus/attachments/20220805/392ff2ee/attachment.htm>


More information about the dbus mailing list