On Wed, Jul 24, 2026, Ján Tomko wrote:
> This can lead to duplicit timer IDs - at least at startup, the daemon
> sets some long-lasting timers.
>
> Can we instead change this to use long long int?
>
> Using unsigned for this would require rewriting more code.
>
> Jano


You're right, resetting to 1 could cause duplicate timer IDs since
the auto-shutdown timer and CPU/memory collection timer 
are created at startup and live for the entire lifetime of the daemon.


I agree that changing to long long int is the correct approach. This
requires changing the timer ID type in:


- vireventglib.c: nexttimer, virEventGLibTimeout.timer
- virevent.h/c: virEventAddTimeout() return type, virEventRemoveTimeout()
  and virEventUpdateTimeout() parameters
- All callers that store timer IDs


This changes the public event API (virEventAddTimeout etc.) which is
declared in libvirt-event.h. But since timer IDs are opaque
handles, the impact on existing callers is just variable type changes
(int -> long long).


I'll prepare v2 with this approach.


[email protected]
[email protected]



        



         原始邮件
         
       
发件人:Ján Tomko <[email protected]&gt;
发件时间:2026年7月24日 19:28
收件人:Yong Chen <[email protected]&gt;
抄送:devel <[email protected]&gt;
主题:Re: [PATCH 1/2] util: Guard against integer overflow in nexttimer



       
On&nbsp;a&nbsp;Thursday&nbsp;in&nbsp;2026,&nbsp;Yong&nbsp;Chen&nbsp;via&nbsp;Devel&nbsp;wrote:
&gt;The&nbsp;'nexttimer'&nbsp;variable&nbsp;is&nbsp;a&nbsp;static&nbsp;int&nbsp;that&nbsp;starts&nbsp;at&nbsp;1&nbsp;and&nbsp;is
&gt;incremented&nbsp;every&nbsp;time&nbsp;a&nbsp;new&nbsp;timeout&nbsp;is&nbsp;registered&nbsp;via
&gt;virEventGLibTimeoutAdd.&nbsp;After&nbsp;running&nbsp;for&nbsp;a&nbsp;long&nbsp;period&nbsp;of&nbsp;time
&gt;(many&nbsp;months/years&nbsp;with&nbsp;frequent&nbsp;client&nbsp;connections),&nbsp;nexttimer
&gt;can&nbsp;overflow&nbsp;past&nbsp;INT_MAX&nbsp;and&nbsp;become&nbsp;negative.
&gt;
&gt;A&nbsp;negative&nbsp;timer&nbsp;ID&nbsp;causes&nbsp;multiple&nbsp;problems:
&gt;1.&nbsp;virKeepAliveStart:&nbsp;'if&nbsp;(ka-&gt;timer&nbsp;<&nbsp;0)'&nbsp;returns&nbsp;true,&nbsp;skipping
&gt;&nbsp;&nbsp;&nbsp;virObjectRef()&nbsp;which&nbsp;is&nbsp;needed&nbsp;to&nbsp;hold&nbsp;the&nbsp;timer's&nbsp;reference&nbsp;to
&gt;&nbsp;&nbsp;&nbsp;the&nbsp;keepalive&nbsp;object.&nbsp;This&nbsp;leads&nbsp;to&nbsp;premature&nbsp;object&nbsp;freeing.
&gt;2.&nbsp;virKeepAliveStop:&nbsp;'if&nbsp;(ka-&gt;timer&nbsp;&gt;&nbsp;0)'&nbsp;returns&nbsp;false,&nbsp;skipping
&gt;&nbsp;&nbsp;&nbsp;virEventRemoveTimeout().&nbsp;The&nbsp;GSource&nbsp;is&nbsp;never&nbsp;destroyed,&nbsp;causing
&gt;&nbsp;&nbsp;&nbsp;a&nbsp;use-after-free&nbsp;when&nbsp;the&nbsp;timer&nbsp;fires&nbsp;on&nbsp;the&nbsp;freed&nbsp;object.
&gt;3.&nbsp;virNetServerClientNew:&nbsp;'if&nbsp;(client-&gt;sockTimer&nbsp;<&nbsp;0)'&nbsp;returns&nbsp;true,
&gt;&nbsp;&nbsp;&nbsp;causing&nbsp;client&nbsp;creation&nbsp;to&nbsp;fail&nbsp;with&nbsp;'Connection&nbsp;reset&nbsp;by&nbsp;peer'.
&gt;
&gt;In&nbsp;a&nbsp;production&nbsp;environment&nbsp;running&nbsp;for&nbsp;1&nbsp;year&nbsp;and&nbsp;8&nbsp;months,
&gt;nexttimer&nbsp;overflowed&nbsp;and&nbsp;accumulated&nbsp;282&nbsp;million&nbsp;leaked&nbsp;timer
&gt;entries,&nbsp;consuming&nbsp;19.6GB&nbsp;of&nbsp;memory.
&gt;
&gt;Fix&nbsp;by&nbsp;resetting&nbsp;nexttimer&nbsp;to&nbsp;1&nbsp;when&nbsp;it&nbsp;overflows&nbsp;below&nbsp;1,&nbsp;ensuring
&gt;timer&nbsp;IDs&nbsp;are&nbsp;always&nbsp;positive.
&gt;
&gt;Signed-off-by:&nbsp;Yong&nbsp;Chen&nbsp;<[email protected]&gt;
&gt;---
&gt;&nbsp;src/util/vireventglib.c&nbsp;|&nbsp;3&nbsp;+++
&gt;&nbsp;1&nbsp;file&nbsp;changed,&nbsp;3&nbsp;insertions(+)
&gt;
&gt;diff&nbsp;--git&nbsp;a/src/util/vireventglib.c&nbsp;b/src/util/vireventglib.c
&gt;index&nbsp;6c54f62123..6fe23b3b7d&nbsp;100644
&gt;---&nbsp;a/src/util/vireventglib.c
&gt;+++&nbsp;b/src/util/vireventglib.c
&gt;@@&nbsp;-341,6&nbsp;+341,9&nbsp;@@&nbsp;virEventGLibTimeoutAdd(int&nbsp;interval,
&gt;
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data&nbsp;=&nbsp;g_new0(struct&nbsp;virEventGLibTimeout,&nbsp;1);
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data-&gt;timer&nbsp;=&nbsp;nexttimer++;
&gt;+&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Guard&nbsp;against&nbsp;integer&nbsp;overflow:&nbsp;timer&nbsp;IDs&nbsp;must&nbsp;be&nbsp;positive&nbsp;*/
&gt;+&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(nexttimer&nbsp;<&nbsp;1)
&gt;+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nexttimer&nbsp;=&nbsp;1;

This&nbsp;can&nbsp;lead&nbsp;to&nbsp;duplicit&nbsp;timer&nbsp;IDs&nbsp;-&nbsp;at&nbsp;least&nbsp;at&nbsp;startup,&nbsp;the&nbsp;daemon
sets&nbsp;some&nbsp;long-lasting&nbsp;timers.

Can&nbsp;we&nbsp;instead&nbsp;change&nbsp;this&nbsp;to&nbsp;use&nbsp;long&nbsp;long&nbsp;int?

Using&nbsp;unsigned&nbsp;for&nbsp;this&nbsp;would&nbsp;require&nbsp;rewriting&nbsp;more&nbsp;code.

Jano

&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data-&gt;interval&nbsp;=&nbsp;interval;
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data-&gt;cb&nbsp;=&nbsp;cb;
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data-&gt;opaque&nbsp;=&nbsp;opaque;
&gt;--&nbsp;
&gt;2.55.0.windows.3
&gt;

Reply via email to