[libvirt] [PATCH] qemu: fix msg could be a wild pointer in qemuMonitorIOProcess()
Peter Krempa
pkrempa at redhat.com
Wed Jun 6 09:19:21 UTC 2018
On Wed, Jun 06, 2018 at 11:46:07 +0800, zhuweilun wrote:
>
>
> 在 2018/6/5 15:10, Peter Krempa 写道:
> > On Tue, Jun 05, 2018 at 10:14:39 +0800, Shannon Zhao wrote:
> >> From: Weilun Zhu <zhuweilun at huawei.com>
> >>
> >> As qemuMonitorJSONIOProcess() will unlock the qemu monitor, there is
> >> some extreme situation, eg qemu send message to monitor twice in a short
> >> time, where the local viriable 'msg' of qemuMonitorIOProcess() could be
> >> a wild point:
> >>
> >> 1. qemuMonitorSend() assign mon->msg to parameter 'msg', which is alse a
> >> local variable of its caller qemuMonitorJSONCommandWithFd(), cause
> >> eventloop to send message to monitor, then wait condition.
> >> 2. qemu send message to monitor for the first time immediately.
> >> 3. qemuMonitorIOProcess() is called, then wake up the qemuMonitorSend()
> >> thread, but the qemuMonitorSend() thread stuck for a while, which means
> >
> > If you wake up a tread via signalling a condition it _must_ have the
> > mutex locked prior to executing ....
> >
> > Note that after waking up from virCondWait you have the mutex which was
> > passed to it locked.
> >
>
> Yes, it _must_ have the mutex locked prior to executing, but there is still
> a chance that the qemuMonitorIO() hold the mutex faster.
>
> I mean virCondWait wants to wake up after qemuMonitorIOProcess() broadcast,
> but it stuck for a while as cpu pressure or scheduleed out or some other
> reasons. And in such short time, before virCondWait try to hold the mutex,
> qemu has sent message again, qemuMonitorIO() has been called again,
> and hold the mutex successfully. So virCondWait will still wait the mutex
> even qemuMonitorIOProcess() has broadcast.
>
> >> the qemu monitor is still unlocked.
> >> 4. qemu send message to monitor for the second time, such as RTC_CHANGE
> >> event
> >> 5. qemuMonitorIOProcess() is called, the local viriable 'msg' is
> >> assigned to mon->msg.
> >> 6. qemuMonitorIOProcess() call qemuMonitorJSONIOProcess() to deal with
> >> the message
> >> 7. qemuMonitorJSONIOProcess() unlock the qemu monitor, qemuMonitorSend()
> >> thread get the lock and free the mon->msg, assign mon->msg to NULL.
> >
> > The monitor is unlocked in qemuMonitorIO() after finishing processing
> > from the event loop. There is no point where qemuMonitorIOProcess()
> > would not hold the mutex locked.
> >
>
> qemuMonitorJSONIOProcess() is called by qemuMonitorIOProcess() to deal with
> the message, qemuMonitorJSONIOProcess()->qemuMonitorJSONIOProcessLine()->
> qemuMonitorJSONIOProcessEvent->qemuMonitorEmitEvent()->QEMU_MONITOR_CALLBACK
>
> #define QEMU_MONITOR_CALLBACK(mon, ret, callback, ...) \
> do { \
> virObjectRef(mon); \
> virObjectUnlock(mon); \
> if ((mon)->cb && (mon)->cb->callback) \
> (ret) = (mon)->cb->callback(mon, __VA_ARGS__, \
> (mon)->callbackOpaque); \
> virObjectLock(mon); \
> virObjectUnref(mon); \
> } while (0)
Ah, okay I did not notice that these unlock the monitor.
That means that the proposed solution is not correct though.
I think a proper solution is to process the events in the same way
normal messages are processed, which is after the monitor is unlocked,
but that is a rather complex fix.
Other possibility is to re-acquire the 'msg' object after the call to
qemuMonitorJSONIOProcess returns. This requires adding a comment why is
it necessary
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20180606/3db3de67/attachment-0001.sig>
More information about the libvir-list
mailing list