[libvirt] using virSetUIDGID() with unprivileged qemu defeats setuid helper

Hi, I recently experienced that my qemu guest (which I'm using with unprivileged user) fails to start with: error: internal error process exited while connecting to monitor: chardev: opening backend "pty" failed This happens upon trying to facilitate the <serial type='pty'> <target port='0'/> </serial> <console type='pty'> <target type='serial' port='0'/> </console> stanzas, for which qemu wants to grab a pty through openpty(3). openpty needs to have the assigned pty to be chown'd to the qemu user, which is attempted via running the setuid helper program pt_chown. However, chown(2) fails with EPERM. The culprit seems to be the commits v1.0.3-rc1~113: util: virSetUIDGIDWithCaps - change uid while keeping caps v1.0.3-rc1~112: util: maintain caps when running command with uid != 0 which change how capabilities are manipulated before program execution. Just immediately before the execve(2) call, the qemu process used to have the following capabilities: CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffffffffffff since said commits, it looks like: CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffe000000000 as far as my capability-noob eyes can see, the bounding set lacks CAP_CHOWN and thus pt_chown won't attain CAP_CHOWN despite running on uid 0, and the EPERM is triggered. How could we fix it? Qemu invocation should be customized or virExec() adjusted? Or is there some configuration workaround? (For the record, I've seen it on Arch Linux; tried their binary package and also my own builds, which included a current git checkout.) Thanks Csaba

On 03/10/2013 10:25 PM, Csaba Henk wrote:
Hi,
I recently experienced that my qemu guest (which I'm using with unprivileged user) fails to start with:
error: internal error process exited while connecting to monitor: chardev: opening backend "pty" failed
This happens upon trying to facilitate the
<serial type='pty'> <target port='0'/> </serial> <console type='pty'> <target type='serial' port='0'/> </console>
stanzas, for which qemu wants to grab a pty through openpty(3). openpty needs to have the assigned pty to be chown'd to the qemu user, which is attempted via running the setuid helper program pt_chown. However, chown(2) fails with EPERM.
Thanks for the analysis.
The culprit seems to be the commits
v1.0.3-rc1~113: util: virSetUIDGIDWithCaps - change uid while keeping caps v1.0.3-rc1~112: util: maintain caps when running command with uid != 0
which change how capabilities are manipulated before program execution.
Just immediately before the execve(2) call, the qemu process used to have the following capabilities:
CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffffffffffff
since said commits, it looks like:
CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffe000000000
We are intentionally dropping capability bits; however, your report means we need to think twice about dropping CAP_CHOWN when there is a pty in play.
as far as my capability-noob eyes can see, the bounding set lacks CAP_CHOWN and thus pt_chown won't attain CAP_CHOWN despite running on uid 0, and the EPERM is triggered.
How could we fix it? Qemu invocation should be customized or virExec() adjusted? Or is there some configuration workaround?
Ideally, we would fix libvirt to open the pty and then hand the fd to qemu via SCM_RIGHTS, rather than letting qemu have to keep CAP_CHOWN. That way, qemu will never need to spawn the helper pt_chown app, and the lack of the capability would not be an issue. But if that doesn't work out, then the fact that we can hot-plug a console means that we cannot know, at qemu start time, whether a later operation would hotplug a pty, so we may be forced to leave CAP_CHWON in the bounding set of all qemu processes. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Mon, Mar 11, 2013 at 01:21:48PM -0600, Eric Blake wrote:
On 03/10/2013 10:25 PM, Csaba Henk wrote:
Hi,
I recently experienced that my qemu guest (which I'm using with unprivileged user) fails to start with:
error: internal error process exited while connecting to monitor: chardev: opening backend "pty" failed
This happens upon trying to facilitate the
<serial type='pty'> <target port='0'/> </serial> <console type='pty'> <target type='serial' port='0'/> </console>
stanzas, for which qemu wants to grab a pty through openpty(3). openpty needs to have the assigned pty to be chown'd to the qemu user, which is attempted via running the setuid helper program pt_chown. However, chown(2) fails with EPERM.
Thanks for the analysis.
The culprit seems to be the commits
v1.0.3-rc1~113: util: virSetUIDGIDWithCaps - change uid while keeping caps v1.0.3-rc1~112: util: maintain caps when running command with uid != 0
which change how capabilities are manipulated before program execution.
Just immediately before the execve(2) call, the qemu process used to have the following capabilities:
CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffffffffffff
since said commits, it looks like:
CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: ffffffe000000000
We are intentionally dropping capability bits; however, your report means we need to think twice about dropping CAP_CHOWN when there is a pty in play.
as far as my capability-noob eyes can see, the bounding set lacks CAP_CHOWN and thus pt_chown won't attain CAP_CHOWN despite running on uid 0, and the EPERM is triggered.
How could we fix it? Qemu invocation should be customized or virExec() adjusted? Or is there some configuration workaround?
Ideally, we would fix libvirt to open the pty and then hand the fd to qemu via SCM_RIGHTS, rather than letting qemu have to keep CAP_CHOWN. That way, qemu will never need to spawn the helper pt_chown app, and the lack of the capability would not be an issue. But if that doesn't work out, then the fact that we can hot-plug a console means that we cannot know, at qemu start time, whether a later operation would hotplug a pty, so we may be forced to leave CAP_CHWON in the bounding set of all qemu processes.
'pt_chown' is a setuid helper program that GLibc can used to chown a PTY to the current user. It is however obsolete and no correctly configured Linux distro should require it anymore, since the dynamic devpts filesystem will provide a PTY that already has the correct ownership. As such it is correct that libvirt is blocking execution of pt_chown. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Csaba Henk
-
Daniel P. Berrange
-
Eric Blake