[libvirt] [PATCH 06/12] [v7] virNodeGetCPUStats: Implement linux support

Eric Blake eblake at redhat.com
Tue Jun 14 22:00:11 UTC 2011


On 06/14/2011 03:40 AM, Daniel P. Berrange wrote:
> On Tue, Jun 14, 2011 at 10:15:36AM +0100, Daniel P. Berrange wrote:
>> On Tue, Jun 07, 2011 at 10:02:55AM +0900, Minoru Usui wrote:
>>> virNodeGetCPUStats: Implement linux support
>>>
>>> Signed-off-by: Minoru Usui <usui at mxm.nes.nec.co.jp>
>>> +#define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK))
>>> +#define CPU_HEADER_LEN 8
>>> +
>>> +int linuxNodeGetCPUStats(FILE *procstat,
>>> +                         int cpuNum,
>>> +                         virCPUStatsPtr params,
>>> +                         int *nparams)
>>> +{
>>> +    int ret = -1;
>>> +    char line[1024];
>>> +    unsigned long long usr, ni, sys, idle, iowait;
>>> +    unsigned long long irq, softirq, steal, guest, guest_nice;
>>> +    char cpu_header[CPU_HEADER_LEN];

>>> +    } else {
>>> +        sprintf(cpu_header, "cpu%d", cpuNum);
>>> +    }
>>
>> cpu_header is declared to be 8 bytes in size, which only allows
>> for integers upto 4 digits long, before we get a buffer overflow
>> here.
>>
>> gnulib has some macro which can be used to declare a string buffer
>> large enough to hold an integer, but I can't remember what the
>> macro is called right now. Hopefully Eric will remind us shortly....
> 
> Jim Meyering reminded me that it is INT_BUFSIZE_BOUND. So eg you
> want todo
> 
>    char cpu_header[3 + INT_BUFSIZE_BOUND(cpuNum) + 1];
> 
> to allow enough space for 'cpu' + any cpuNum value formatted as
> a string + the trailing NULL.

Actually, INT_BUFSIZE_BOUND already includes space for the trailing NUL,
so the +1 is not needed.

> ACK if the buffer overflow problem is solved

Also, 'make syntax-check' complained about cppi indentation, and the
fact that we've blacklisted sprintf (use snprintf instead).  Plus you
had some weird indentation.

Here's what I squashed before pushing:

diff --git i/src/nodeinfo.c w/src/nodeinfo.c
index 235a68a..bdf8f8a 100644
--- i/src/nodeinfo.c
+++ w/src/nodeinfo.c
@@ -66,10 +66,10 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
                              virNodeInfoPtr nodeinfo,
                              bool need_hyperthreads);

-int linuxNodeGetCPUStats(FILE *procstat,
-                         int cpuNum,
-                         virCPUStatsPtr params,
-                         int *nparams);
+static int linuxNodeGetCPUStats(FILE *procstat,
+                                int cpuNum,
+                                virCPUStatsPtr params,
+                                int *nparams);

 /* Return the positive decimal contents of the given
  * CPU_SYS_PATH/cpu%u/FILE, or -1 on error.  If MISSING_OK and the
@@ -384,8 +384,7 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
     return 0;
 }

-#define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK))
-#define CPU_HEADER_LEN 8
+# define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK))

 int linuxNodeGetCPUStats(FILE *procstat,
                          int cpuNum,
@@ -396,7 +395,7 @@ int linuxNodeGetCPUStats(FILE *procstat,
     char line[1024];
     unsigned long long usr, ni, sys, idle, iowait;
     unsigned long long irq, softirq, steal, guest, guest_nice;
-    char cpu_header[CPU_HEADER_LEN];
+    char cpu_header[3 + INT_BUFSIZE_BOUND(cpuNum)];

     if ((*nparams) == 0) {
         /* Current number of cpu stats supported by linux */
@@ -414,7 +413,7 @@ int linuxNodeGetCPUStats(FILE *procstat,
     if (cpuNum == VIR_CPU_STATS_ALL_CPUS) {
         strcpy(cpu_header, "cpu");
     } else {
-        sprintf(cpu_header, "cpu%d", cpuNum);
+        snprintf(cpu_header, sizeof(cpu_header), "cpu%d", cpuNum);
     }

     while (fgets(line, sizeof(line), procstat) != NULL) {
@@ -436,7 +435,7 @@ int linuxNodeGetCPUStats(FILE *procstat,

                 switch (i) {
                 case 0: /* fill kernel cpu time here */
-                    if (virStrcpyStatic(param->field,
VIR_CPU_STATS_KERNEL)== NULL) {
+                    if (virStrcpyStatic(param->field,
VIR_CPU_STATS_KERNEL) == NULL) {
                         nodeReportError(VIR_ERR_INTERNAL_ERROR,
                                         "%s", _("Field kernel cpu time
too long for destination"));
                         goto cleanup;
@@ -528,22 +527,23 @@ int nodeGetCPUStats(virConnectPtr conn
ATTRIBUTE_UNUSED,
                     int cpuNum,
                     virCPUStatsPtr params,
                     int *nparams,
-                    unsigned int flags ATTRIBUTE_UNUSED)
+                    unsigned int flags)
 {
+    virCheckFlags(0, -1);

 #ifdef __linux__
     {
-    int ret;
-    FILE *procstat = fopen(PROCSTAT_PATH, "r");
-    if (!procstat) {
-        virReportSystemError(errno,
-                             _("cannot open %s"), PROCSTAT_PATH);
-        return -1;
-    }
-    ret = linuxNodeGetCPUStats(procstat, cpuNum, params, nparams);
-    VIR_FORCE_FCLOSE(procstat);
+        int ret;
+        FILE *procstat = fopen(PROCSTAT_PATH, "r");
+        if (!procstat) {
+            virReportSystemError(errno,
+                                 _("cannot open %s"), PROCSTAT_PATH);
+            return -1;
+        }
+        ret = linuxNodeGetCPUStats(procstat, cpuNum, params, nparams);
+        VIR_FORCE_FCLOSE(procstat);

-    return ret;
+        return ret;
     }
 #else
     nodeReportError(VIR_ERR_NO_SUPPORT, "%s",

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 619 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20110614/3e3dbac4/attachment-0001.sig>


More information about the libvir-list mailing list