Switching to bi-directional stdin when qrexec-agent and child run as different users

9 views
Skip to first unread message

Simon Gaiser

unread,
Oct 7, 2021, 8:12:22 PM10/7/21
to Marek Marczykowski-Górecki, qubes-devel, Demi Marie Obenour
Hi Marek and list,

a qrexec service started by qrexec-agent (directly or via
qrexec-fork-server) can request that instead of using stdin and stdout
both side switch to using stdin bi-directional. To do so it needs to
send SIGUSR1 to QREXEC_AGENT_PID.

According to the git history [1] this has been added for usbip. As
hinted in the commit message and in the comment [2] in the code this
mechanism has a problem. To send a signal you need to be root or run as
the same user as the receiving process.

This lead to a corner case in the Python port of split-gpg2 [3] that
tried to always switch to the bi-directional mode. During normal
operation things worked since it's spawned through qrexec-fork-server
that is running as user. But if the VM wasn't running the qrexec service
in the freshly booted VM is spawned directly by qrexec-agent that runs
as root and therefore sending SIGUSR1 failed.

For split-gpg2 I switched, at least for now, to always use stdin/-out
(maintaining two code paths would be ugly).

Do we have plans to improve this?

Beside the uspip case, are there any advantages of having a
bi-directional stdin?

Simon

[1]: https://github.com/QubesOS/qubes-core-agent-linux/commit/c1cb78e0e8e2e6090c32e2c1cddc9f8bcbd8399e
[2]: https://github.com/QubesOS/qubes-core-qrexec/blob/339f79a13403ce240e4e0748717d8fb9674b31b3/agent/qrexec-agent-data.c#L215
[3]: https://github.com/HW42/qubes-app-linux-split-gpg2
OpenPGP_0xFE1A17CE69D0DCAC.asc
OpenPGP_signature

Marek Marczykowski-Górecki

unread,
Oct 7, 2021, 8:22:04 PM10/7/21
to Simon Gaiser, qubes-devel, Demi Marie Obenour
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

On Fri, Oct 08, 2021 at 02:12:08AM +0200, Simon Gaiser wrote:
> Hi Marek and list,
>
> a qrexec service started by qrexec-agent (directly or via
> qrexec-fork-server) can request that instead of using stdin and stdout
> both side switch to using stdin bi-directional. To do so it needs to
> send SIGUSR1 to QREXEC_AGENT_PID.
>
> According to the git history [1] this has been added for usbip. As
> hinted in the commit message and in the comment [2] in the code this
> mechanism has a problem. To send a signal you need to be root or run as
> the same user as the receiving process.
>
> This lead to a corner case in the Python port of split-gpg2 [3] that
> tried to always switch to the bi-directional mode. During normal
> operation things worked since it's spawned through qrexec-fork-server
> that is running as user. But if the VM wasn't running the qrexec service
> in the freshly booted VM is spawned directly by qrexec-agent that runs
> as root and therefore sending SIGUSR1 failed.

I think fixing that "TODO" shouldn't be that hard. The data handling
process (the one pointed with QREXEC_AGENT_PID) is already a separate
process, and I don't think it needs to keep root privileges.
This should be rather simple change, am I missing anything?

> For split-gpg2 I switched, at least for now, to always use stdin/-out
> (maintaining two code paths would be ugly).
>
> Do we have plans to improve this?
>
> Beside the uspip case, are there any advantages of having a
> bi-directional stdin?

Yes, I'd consider making split-gpg2 a socket-based service (with one
process handling several requests, to avoid process startup delay). For
this, it needs to transfer data over a single socket FD.
- --
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEEhrpukzGPukRmQqkK24/THMrX1ywFAmFfjyYACgkQ24/THMrX
1ywkiQf/VQ4pt40jsf/5YTn9OW9hTrfkh7ykMqo+X2Te0VKEuopu8XeBsvyZK1Hv
/Up+clWj5RnCI+33jrV4wK56ddRBPiogenyrbBrel36hP0AXBHtljU4lIFmOu388
HbnOo4OQiaTK1ZuHMxaC2t56mThgCCrlarlvw020uzrTncI0nNvgdLmWZf0bgCJX
SEgsWpBNzEOdAXia0uY19l0jXM4EvFEEbaE7EaaXqfXyY7D+qtuF9HSNMid58fyN
3FhvtuwHcTBgD2/Vdd9GeU93quCdXtc/H0E7zL0XO8HP/2V0eMkzGG2oWvc5Klrd
q747t9tYoKqfgYQj1SvLU4y0Wa1ddg==
=7TGX
-----END PGP SIGNATURE-----

Simon Gaiser

unread,
Oct 7, 2021, 9:26:21 PM10/7/21
to Marek Marczykowski-Górecki, qubes-devel, Demi Marie Obenour
Marek Marczykowski-Górecki:
>> a qrexec service started by qrexec-agent (directly or via
>> qrexec-fork-server) can request that instead of using stdin and
>> stdout both side switch to using stdin bi-directional. To do so it
>> needs to send SIGUSR1 to QREXEC_AGENT_PID.
>
>> According to the git history [1] this has been added for usbip. As
>> hinted in the commit message and in the comment [2] in the code this
>> mechanism has a problem. To send a signal you need to be root or run
>> as the same user as the receiving process.
>
>> This lead to a corner case in the Python port of split-gpg2 [3] that
>> tried to always switch to the bi-directional mode. During normal
>> operation things worked since it's spawned through qrexec-fork-server
>> that is running as user. But if the VM wasn't running the qrexec
>> service in the freshly booted VM is spawned directly by qrexec-agent
>> that runs as root and therefore sending SIGUSR1 failed.
>
> I think fixing that "TODO" shouldn't be that hard. The data handling
> process (the one pointed with QREXEC_AGENT_PID) is already a separate
> process, and I don't think it needs to keep root privileges. This
> should be rather simple change, am I missing anything?

Might be that easy. Didn't checked yet.

>> For split-gpg2 I switched, at least for now, to always use stdin/-out
>> (maintaining two code paths would be ugly).
>
>> Do we have plans to improve this?
>
>> Beside the uspip case, are there any advantages of having a
>> bi-directional stdin?
>
> Yes, I'd consider making split-gpg2 a socket-based service (with one
> process handling several requests, to avoid process startup delay).
> For this, it needs to transfer data over a single socket FD.

But in that case split-gpg2 would open one unix socket and accept
connections there. So the above mechanism wouldn't be needed at all, or
do I miss something?

OpenPGP_signature

Marek Marczykowski-Górecki

unread,
Oct 7, 2021, 9:42:33 PM10/7/21
to Simon Gaiser, qubes-devel, Demi Marie Obenour
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

On Fri, Oct 08, 2021 at 03:26:11AM +0200, Simon Gaiser wrote:
> Marek Marczykowski-Górecki:
> > Yes, I'd consider making split-gpg2 a socket-based service (with one
> > process handling several requests, to avoid process startup delay).
> > For this, it needs to transfer data over a single socket FD.
>
> But in that case split-gpg2 would open one unix socket and accept
> connections there. So the above mechanism wouldn't be needed at all, or
> do I miss something?

Indeed, switching wouldn't be needed in that case. Using a single FD for
both reading and writing would be.


- --
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEEhrpukzGPukRmQqkK24/THMrX1ywFAmFfogMACgkQ24/THMrX
1yzNvwf/blB33gjzEASn2O8tQVyNX+pU2qzHntidNjacL2InsfB+P7ls7eCozK4l
m/sgeujhJHY+n3BpHdoM/U8v6Man5/a080DpSDIFoxG/2GYAvLNZUS4u3yb2afJ8
Nahnv2MdrigWTNm6buhFS+LK0UjF6nIetGOzk9hOFdJi6AZxV8LG18LuvJUtJlue
Q0gmmtFnfsd5YbMuYnHSSYWO0AoXfJcnrnryCgHC21ciAHdUhep2GPiIgwe+Jxd6
pcMoBPH36nvPYsZo721Rx/3yEG2Mb5Nz8ychHWIh5LixuqqmkAwTKqhuHJOHqIQ8
fauFvbEGBpSElgGy5ll2NdY3reqHaA==
=/2wR
-----END PGP SIGNATURE-----

Demi Marie Obenour

unread,
Oct 11, 2021, 9:13:25 AM10/11/21
to Marek Marczykowski-Górecki, Simon Gaiser, qubes-devel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

On Fri, Oct 08, 2021 at 02:21:58AM +0200, Marek Marczykowski-Górecki wrote:
> On Fri, Oct 08, 2021 at 02:12:08AM +0200, Simon Gaiser wrote:
> > Hi Marek and list,
> >
> > a qrexec service started by qrexec-agent (directly or via
> > qrexec-fork-server) can request that instead of using stdin and stdout
> > both side switch to using stdin bi-directional. To do so it needs to
> > send SIGUSR1 to QREXEC_AGENT_PID.
> >
> > According to the git history [1] this has been added for usbip. As
> > hinted in the commit message and in the comment [2] in the code this
> > mechanism has a problem. To send a signal you need to be root or run as
> > the same user as the receiving process.
> >
> > This lead to a corner case in the Python port of split-gpg2 [3] that
> > tried to always switch to the bi-directional mode. During normal
> > operation things worked since it's spawned through qrexec-fork-server
> > that is running as user. But if the VM wasn't running the qrexec service
> > in the freshly booted VM is spawned directly by qrexec-agent that runs
> > as root and therefore sending SIGUSR1 failed.
>
> I think fixing that "TODO" shouldn't be that hard. The data handling
> process (the one pointed with QREXEC_AGENT_PID) is already a separate
> process, and I don't think it needs to keep root privileges.
> This should be rather simple change, am I missing anything?

I don’t think this is a good idea for two reasons. First, using SIGUSR1
is inherently not very reliable, as it is asynchronous and doesn’t
provide any confirmation of signal receipt. A better approach would be
to pass an AF_UNIX stream socket as file descriptor 3, or else just
unconditionally accept data on either file descriptor 0 or 1. Second,
this would allow the child process to ptrace() the parent process and
obtain access to Xen file descriptors, which could potentially be used
to escalate privilege within the qube. While this isn’t an explicit
security boundary in Qubes OS, my understanding is that Qubes OS doesn’t
try to deliberately weaken it either.

> > For split-gpg2 I switched, at least for now, to always use stdin/-out
> > (maintaining two code paths would be ugly).
> >
> > Do we have plans to improve this?
> >
> > Beside the uspip case, are there any advantages of having a
> > bi-directional stdin?
>
> Yes, I'd consider making split-gpg2 a socket-based service (with one
> process handling several requests, to avoid process startup delay). For
> this, it needs to transfer data over a single socket FD.

I fully support this, but with two significant caveats. The first is
that one must ensure the socket is present and listening before qrexec
tries to connect to it. This isn’t trivial for a service not running as
root. The second is that right now, one can use user= directives in
qrexec policy to control which qube has access to which keys. While
this is not best practice, on memory-constrained hardware it can be the
difference between being able to use split-gpg and not being able to do
so.

- --
Sincerely,
Demi Marie Obenour (she/her/hers)
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEdodNnxM2uiJZBxxxsoi1X/+cIsEFAmFkOG4ACgkQsoi1X/+c
IsET/g//TSCwHp1MFIJvSSMc/KqqOWcMc8DAFI0qW08SlNTeXb2Cpc/p9iNbrhih
9zDZEDGG8s188hQwzn3hACJot1ibBxGQr6T6zqx/zm7iWZKYU/8eSDzW61HCtnuf
CUpPCHqPeMxjDpgfKzo7JpooZ4HB1oVkkXjpaiJMCShnXGHYHXf22vV/Xh0yaapi
XDPTtKACHqqBgrlogzM8mbt8FX/KraCMY2cvheZA/l+gGbIIamvr/VxSnnOFfN8O
o3rSYJOICDgSCrl2DWnpupB07TZYg8mmsUwnOYWNCJay7zAmC6eixFPbFYrmrFNW
Pm5w/HZLteS6sS1mwq1Ap8p1zlXSkTqPLay2Qt+S3ip6h7hE0JnXwbqN7C4jAMlp
THA+aqmJZQsusZ7TM7H9LeFViIJRRKjWJ98JEu5n6zE65dmnJC5xgHR0PkCpHY8q
oYB4CM628DWffOsvseXwQapbjk5JSAjr/z9zHK/8B6n7EWYzrw1UPMjF0bs0WHdg
dHdB8NT42hs+ZP2xOuGgylLtsYxuTqnhnVp2VLLGgl5edUdmd9312JkwcwPfskTy
HvsC4+4V/3mLvnlkDTvH36hzeGoSqkPtAUrW4v5+ZEmDjfYDOFxNMjDTys4jGoxE
dBNWMhUBEdgsShWsJ+rZVtU9h+TFKKSj08uakeHQPLCVwVwfS7k=
=5Xrk
-----END PGP SIGNATURE-----

Marek Marczykowski-Górecki

unread,
Oct 11, 2021, 10:28:10 AM10/11/21
to Demi Marie Obenour, Simon Gaiser, qubes-devel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

I don't think it was ever an issue, but theoretically you are correct.

> A better approach would be
> to pass an AF_UNIX stream socket as file descriptor 3,

Then, the qrexec doesn't know where to send the data...

> or else just
> unconditionally accept data on either file descriptor 0 or 1.

Almost, closing FD 1 must not be sent as EOF (after which, sending more
data over FD 0 wouldn't be possible anymore). And BTW, a heuristic of
"don't send EOF on FD 1 close, if any data was received over FD 0
already" won't work, as for the usbip connection, the actual data is
exchanged only after FD is passed on to the kernel (after closing other
FDs).

> Second,
> this would allow the child process to ptrace() the parent process and
> obtain access to Xen file descriptors, which could potentially be used
> to escalate privilege within the qube. While this isn’t an explicit
> security boundary in Qubes OS, my understanding is that Qubes OS doesn’t
> try to deliberately weaken it either.

Well, user processes must have the ability to open vchan connections
anyway, either for qrexec-client-vm to work, or for qrexec-fork-server.

> > > For split-gpg2 I switched, at least for now, to always use stdin/-out
> > > (maintaining two code paths would be ugly).
> > >
> > > Do we have plans to improve this?
> > >
> > > Beside the uspip case, are there any advantages of having a
> > > bi-directional stdin?
> >
> > Yes, I'd consider making split-gpg2 a socket-based service (with one
> > process handling several requests, to avoid process startup delay). For
> > this, it needs to transfer data over a single socket FD.
>
> I fully support this, but with two significant caveats. The first is
> that one must ensure the socket is present and listening before qrexec
> tries to connect to it. This isn’t trivial for a service not running as
> root.

We could have a system unit with User= setting.

> The second is that right now, one can use user= directives in
> qrexec policy to control which qube has access to which keys. While
> this is not best practice, on memory-constrained hardware it can be the
> difference between being able to use split-gpg and not being able to do
> so.

That's true. In fact it's yet another case, where overriding the call
argument at the policy level could be useful (something I consider
adding for a long time already) - then you could have different sockets
for different users.

- --
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEEhrpukzGPukRmQqkK24/THMrX1ywFAmFkSfAACgkQ24/THMrX
1ywmewf8CMW2/gkqaS9HUjCmbtzPorNJaeCH12fWsgj1eiA9AY85s4aesF0a74Nr
VZOzven0UANGKaVD3ZH77uTi+0h8Wu57QAOvclKzQqTES5MrOdC0WKKqjjGV6WYP
Mf1P0w/828/DPcsKt13Og8OchbuFTLX46ricv3W6awyPkd4e3MyJIIP+J/x3qRUd
TSvy6/kci4q3YOqUSUu9FjA2t8+FZuHx+KUxMSgQYFDSie1VoVlr5luORkzwDwge
Z4DtoRgWwGk7esOV0x9c9SaKM33GRpDxzbv727mZ1C5VX/HIGeKvIMXmPEVJENW8
kknlUzx/kWVwiMkq7kGGBw0bv53Ayw==
=FtlZ
-----END PGP SIGNATURE-----

Demi Marie Obenour

unread,
Oct 11, 2021, 10:35:17 AM10/11/21
to Marek Marczykowski-Górecki, Simon Gaiser, qubes-devel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Has this ever had any users other than USB pass-through? If not, it
might explain some of the random failures there.

> > A better approach would be
> > to pass an AF_UNIX stream socket as file descriptor 3,
>
> Then, the qrexec doesn't know where to send the data...

I meant to use file descriptor 3 for out-of-band control messages. On
further thought, I would actually prefer a *datagram* socket, with
checks that the message actually came from the correct child process.

> > or else just
> > unconditionally accept data on either file descriptor 0 or 1.
>
> Almost, closing FD 1 must not be sent as EOF (after which, sending more
> data over FD 0 wouldn't be possible anymore). And BTW, a heuristic of
> "don't send EOF on FD 1 close, if any data was received over FD 0
> already" won't work, as for the usbip connection, the actual data is
> exchanged only after FD is passed on to the kernel (after closing other
> FDs).

That is true.

> > Second,
> > this would allow the child process to ptrace() the parent process and
> > obtain access to Xen file descriptors, which could potentially be used
> > to escalate privilege within the qube. While this isn’t an explicit
> > security boundary in Qubes OS, my understanding is that Qubes OS doesn’t
> > try to deliberately weaken it either.
>
> Well, user processes must have the ability to open vchan connections
> anyway, either for qrexec-client-vm to work, or for qrexec-fork-server.

My understanding is that this typically requires membership in the
“qubes” group, which is the same group that
‘qubes-core-agent-passwordless-root’ gives passwordless sudo access to.

> > > > For split-gpg2 I switched, at least for now, to always use stdin/-out
> > > > (maintaining two code paths would be ugly).
> > > >
> > > > Do we have plans to improve this?
> > > >
> > > > Beside the uspip case, are there any advantages of having a
> > > > bi-directional stdin?
> > >
> > > Yes, I'd consider making split-gpg2 a socket-based service (with one
> > > process handling several requests, to avoid process startup delay). For
> > > this, it needs to transfer data over a single socket FD.
> >
> > I fully support this, but with two significant caveats. The first is
> > that one must ensure the socket is present and listening before qrexec
> > tries to connect to it. This isn’t trivial for a service not running as
> > root.
>
> We could have a system unit with User= setting.

Good point.

> > The second is that right now, one can use user= directives in
> > qrexec policy to control which qube has access to which keys. While
> > this is not best practice, on memory-constrained hardware it can be the
> > difference between being able to use split-gpg and not being able to do
> > so.
>
> That's true. In fact it's yet another case, where overriding the call
> argument at the policy level could be useful (something I consider
> adding for a long time already) - then you could have different sockets
> for different users.

That is a good idea that I had not considered. That said, it does
conflict with having split-gpg2 use the call argument for filtering.

- --
Sincerely,
Demi Marie Obenour
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEdodNnxM2uiJZBxxxsoi1X/+cIsEFAmFkS58ACgkQsoi1X/+c
IsGdbA/+JQpMpMpBd6ah8GUBBRTp0/GcwDF3X/1WLaTj+LxXw6t3y2AeYgF6lmFj
84vjJWl1WSE1aQOOz95No8L4HmbJIkSGRO7OGlggLxRwDOds2ur9h+n0mSeiFNHf
rXg9PntpaJGW5ILpHoTOM6kDoYDHb/PChk+0CEXNedx3OE/+dN2oHshhi5CQHrKv
SMY4x7B3p3jdlmt9XNFIalm9ZPJfs3ZHAUoE+PxfUby5LqR/csiwf0e+3Ix8u6ch
Fwnl0Dtw1c+GFoV3E3gtwuSk020fdJnv6M23ytRJwMpzxX+keP0D/ujzyO/zhgmO
ZajkgEyLCy1TMIc4l4a178ORjoAT3uVl2phATdlojcXFRnXf3IK7wi0S93FozfNe
63k/FLE84Y6Tbszpsmwnh+T7mDWoEOmBV/4/hskHTu6VDLnntT2Mb779iDZODoFh
6I4ReYRxfmM2mQ2yHNa4Bcf8mCEI4KZVeY2rYtOktxNRuPnnITxQk0YIg3JMNICU
MriWb8f6Ntt4sojqSQT7G6JqwDcW+/lrdrXHBVH0vgOOTYGIhDrleMTn6jvggTra
Q0u1eXeZcCiehpZBcjMdWzriKykqtg0UuQ7AIZfnYNq2hjMYVvZYrrKr7H6lbklw
c9zYULMpvL87MPdTBmgvHxq0Kid1YRFOdcQo6sXjrENKCButEfw=
=zvI2
-----END PGP SIGNATURE-----

Marek Marczykowski-Górecki

unread,
Oct 11, 2021, 11:48:19 AM10/11/21
to Demi Marie Obenour, Simon Gaiser, qubes-devel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Can you point at some specific bug reports? I'm only aware of two types
of USB passthrough issues:
- resetting USB device disconnects it (especially an issue for
connecting Android phones, which looks like a device reset on mode
switch)
- unsupported data transfer mode (should be better now, since the
current USBIP driver has XHCI support)

> > > A better approach would be
> > > to pass an AF_UNIX stream socket as file descriptor 3,
> >
> > Then, the qrexec doesn't know where to send the data...
>
> I meant to use file descriptor 3 for out-of-band control messages. On
> further thought, I would actually prefer a *datagram* socket,

I see, but TBH I don't like it that much. This makes writing a service
significantly harder, because (in some cases) it is no longer enough to
use standard read/write (or kill) which you can do trivially in any
language/tool etc, sending/receiving datagram over AF_UNIX is rather
uncommon thing (and often even sending UDP packets requires much less
common API).

On the other hand, I think one can rather easily get confirmation when
the parent qrexec processes the SIGUSR1 - simply by waiting for EOF on FD 1.

An alternative, is to use socket service. If you don't like an extra
process laying around, you can use socket systemd unit, with Accept=true
if necessary. But then, you need to read the service call handshake
before using it for the actual data (not a big deal).

> with
> checks that the message actually came from the correct child process.

No, that's a bad idea. This forces specific process structure of a
service, which will be limiting factor.

> > > or else just
> > > unconditionally accept data on either file descriptor 0 or 1.
> >
> > Almost, closing FD 1 must not be sent as EOF (after which, sending more
> > data over FD 0 wouldn't be possible anymore). And BTW, a heuristic of
> > "don't send EOF on FD 1 close, if any data was received over FD 0
> > already" won't work, as for the usbip connection, the actual data is
> > exchanged only after FD is passed on to the kernel (after closing other
> > FDs).
>
> That is true.
>
> > > Second,
> > > this would allow the child process to ptrace() the parent process and
> > > obtain access to Xen file descriptors, which could potentially be used
> > > to escalate privilege within the qube. While this isn’t an explicit
> > > security boundary in Qubes OS, my understanding is that Qubes OS doesn’t
> > > try to deliberately weaken it either.
> >
> > Well, user processes must have the ability to open vchan connections
> > anyway, either for qrexec-client-vm to work, or for qrexec-fork-server.
>
> My understanding is that this typically requires membership in the
> “qubes” group, which is the same group that
> ‘qubes-core-agent-passwordless-root’ gives passwordless sudo access to.

Yes. Which means, it would only change anything if running service as
an user who is not member of the 'qubes' group.
Depending on what you put into that call argument. It may actually ease
it, for example: qubes.Gpg2+Sign enforced to qubes.Gpg2+Sign+0xKEYID
You may need to create some symlinks to the socket for various
operations, but it shouldn't be an issue.

- --
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEEhrpukzGPukRmQqkK24/THMrX1ywFAmFkXLkACgkQ24/THMrX
1ywWbgf/XzQ2yZHC86gJTlPw8eAd3wa3EZUKrDFZFGgCKgJo4M/nTjAs1EyFsKSP
HATNzKAZqBbg2pMORNNB7cRSr9s6MXgp9G52MFijGeCTTrYabymgDGuQDkd0vLob
kdf60a4edyr8wzBluoxvFaWySugDiHqZM8kdNJup3PtRJjIqLT2p1b811gKvviSX
C+HgcBXZWmnwGZ2OfObsXZ52gONKru7Jyen6yekZk5d7qRZQ7qTohbIMg65tc4Py
rGz7EB/IVFBxd5NdVNNnPltkZ+rY/UHf1QycPCs4Rzc4+ulGN4hf2/gpEHLGx0AS
BkAno4sJj3DtfQBW5UTZoZUCrw6Kgg==
=pSeT
-----END PGP SIGNATURE-----

Demi Marie Obenour

unread,
Oct 11, 2021, 2:48:34 PM10/11/21
to Marek Marczykowski-Górecki, Simon Gaiser, qubes-devel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

That explains why pass-through of an Android phone never worked!

> - unsupported data transfer mode (should be better now, since the
> current USBIP driver has XHCI support)

I am glad to know that that issue is fixed.

> > > > A better approach would be
> > > > to pass an AF_UNIX stream socket as file descriptor 3,
> > >
> > > Then, the qrexec doesn't know where to send the data...
> >
> > I meant to use file descriptor 3 for out-of-band control messages. On
> > further thought, I would actually prefer a *datagram* socket,
>
> I see, but TBH I don't like it that much. This makes writing a service
> significantly harder, because (in some cases) it is no longer enough to
> use standard read/write (or kill) which you can do trivially in any
> language/tool etc, sending/receiving datagram over AF_UNIX is rather
> uncommon thing (and often even sending UDP packets requires much less
> common API).

Good point. It is fairly easy in C, but doing it in most other
languages requires calling the C functions. That said, another (even
simpler) approach would be to treat data read from FD 0 as if it were
read from FD 1, which doesn’t even require sending a signal.

> On the other hand, I think one can rather easily get confirmation when
> the parent qrexec processes the SIGUSR1 - simply by waiting for EOF on FD 1.

I didn’t actually realize this. Since signals can’t actually be *lost*
(merely coalesced), and since only one signal is actually sent, signals
are actually reliable here. And I was not aware that qrexec would close
FD 1 after handling the signal; this allows the child process to confirm
that the signal was received.

FYI, there is a cute trick on Linux to send a signal to one’s parent
process, with no PID reuse race conditions: open a pidfd to the parent
process ID, then (if that succeeds) check that the parent process ID has
not changed. If it has not changed, send the signal via
pidfd_signal(2). In C:

#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>

int send_signal_to_parent(int sig) {
pid_t x = getppid();
int res = -1;
if (x <= 1)
return -1; /* parent in different PID namespace or init */
int fd = syscall(__NR_pidfd_open, x, 0);
if (fd < 0)
return -1; /* pidfd_open failed */
if (x == getppid())
res = syscall(__NR_pidfd_send_signal, fd, sig, (void *)0, 0);
close(fd);
return res;
}

> > with
> > checks that the message actually came from the correct child process.
>
> No, that's a bad idea. This forces specific process structure of a
> service, which will be limiting factor.

Indeed so, good point.

> > > > Second,
> > > > this would allow the child process to ptrace() the parent process and
> > > > obtain access to Xen file descriptors, which could potentially be used
> > > > to escalate privilege within the qube. While this isn’t an explicit
> > > > security boundary in Qubes OS, my understanding is that Qubes OS doesn’t
> > > > try to deliberately weaken it either.
> > >
> > > Well, user processes must have the ability to open vchan connections
> > > anyway, either for qrexec-client-vm to work, or for qrexec-fork-server.
> >
> > My understanding is that this typically requires membership in the
> > “qubes” group, which is the same group that
> > ‘qubes-core-agent-passwordless-root’ gives passwordless sudo access to.
>
> Yes. Which means, it would only change anything if running service as
> an user who is not member of the 'qubes' group.

Correct.

> > > > The second is that right now, one can use user= directives in
> > > > qrexec policy to control which qube has access to which keys. While
> > > > this is not best practice, on memory-constrained hardware it can be the
> > > > difference between being able to use split-gpg and not being able to do
> > > > so.
> > >
> > > That's true. In fact it's yet another case, where overriding the call
> > > argument at the policy level could be useful (something I consider
> > > adding for a long time already) - then you could have different sockets
> > > for different users.
> >
> > That is a good idea that I had not considered. That said, it does
> > conflict with having split-gpg2 use the call argument for filtering.
>
> Depending on what you put into that call argument. It may actually ease
> it, for example: qubes.Gpg2+Sign enforced to qubes.Gpg2+Sign+0xKEYID
> You may need to create some symlinks to the socket for various
> operations, but it shouldn't be an issue.

Indeed so. I hadn’t thought of creating the symlinks.

- --
Sincerely,
Demi Marie Obenour (she/her/hers)
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEdodNnxM2uiJZBxxxsoi1X/+cIsEFAmFkhv0ACgkQsoi1X/+c
IsGgVhAAmNLuFDacJ3X6l4ZOaoo792Y47qNcgHQNeloWYnrvYYFo+WjMwDj3iDx0
ku01DXExpYS10+EUDKc+A2WHX32xHy8RvJN/syMzMUmPCpQHjGpaFdy0tcN9d62k
yJ7AP7E2vNFD97ZCp3CTbWOy9TFs2X1+2Icg9YBOCnKP2zNiNW3D+aozaew65HNM
egCb2Hl14DPpPsDyoSySp3KcSuTzLGv2xA6Lj/lD0j6pVr+athi56+bQiPh5XztL
uRdgksI/G2gC90g/fWFzcYAPf6ul6TdYyWth0okwC4D1Ci5DUScG0JbvUxxX9u65
8jCiBWYoLDRoybrwJ85sGXPJT5ai9xcMO281OA/4VkhhMUbmccBUuOT/hNvZ/zSk
7ve+RVsvyAGPUjkV++/KrObMLzc3NsTlDFQ/Tm6mxvTDxhaFfdCS5gP+hmxq+9ua
2cAkIFy7KQec5xay8g8itHjNpVNeTHKWJFHx8JmsBVHv5yUQqt73w1Q2lpLxwYFy
3PXCORVflikcbPz6MILb5HZgl0yhLpSjZ7Ab3I79dCoVOU5TDBsByNzpZAHWEwV/
ARfkAibcf+Db+NN/IK9Sb8CLIB9O/D547JnR4tOHF+Q/zFYDaFIwFa8KOpU6PBq+
gnLbhmx6hNPLH2klU7gPc1QGfoRfGWorUCxpGTXg/MjM587IbEA=
=9hXh
-----END PGP SIGNATURE-----
Reply all
Reply to author
Forward
0 new messages