virt-host-validate: Allow longer list of CPU flags

On various occasions, virt-host-validate parses /proc/cpuinfo to
learn about CPU flags (see virHostValidateGetCPUFlags()). It does
so, by reading the file line by line until the line with CPU
flags is reached. Then the line is split into individual flags
(using space as a delimiter) and the list of flags is then
iterated over.

This works, except for cases when the line with CPU flags is too
long. Problem is - the line is capped at 1024 bytes and on newer
CPUs (and newer kernels), the line can be significantly longer.
I've seen a line that's ~1200 characters long (with 164 flags
reported).

Switch to unbounded read from the file (getline()).

Resolves: https://issues.redhat.com/browse/RHEL-39969
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
Michal Privoznik 2024-07-23 10:31:27 +02:00
parent 8f3b46e30b
commit e5232f6fd6

View File

@ -106,21 +106,19 @@ virBitmap *virHostValidateGetCPUFlags(void)
{ {
FILE *fp; FILE *fp;
virBitmap *flags = NULL; virBitmap *flags = NULL;
g_autofree char *line = NULL;
size_t linelen = 0;
if (!(fp = fopen("/proc/cpuinfo", "r"))) if (!(fp = fopen("/proc/cpuinfo", "r")))
return NULL; return NULL;
flags = virBitmapNew(VIR_HOST_VALIDATE_CPU_FLAG_LAST); flags = virBitmapNew(VIR_HOST_VALIDATE_CPU_FLAG_LAST);
do { while (getline(&line, &linelen, fp) > 0) {
char line[1024];
char *start; char *start;
g_auto(GStrv) tokens = NULL; g_auto(GStrv) tokens = NULL;
GStrv next; GStrv next;
if (!fgets(line, sizeof(line), fp))
break;
/* The line we're interested in is marked differently depending /* The line we're interested in is marked differently depending
* on the architecture, so check possible prefixes */ * on the architecture, so check possible prefixes */
if (!STRPREFIX(line, "flags") && if (!STRPREFIX(line, "flags") &&
@ -129,11 +127,9 @@ virBitmap *virHostValidateGetCPUFlags(void)
!STRPREFIX(line, "facilities")) !STRPREFIX(line, "facilities"))
continue; continue;
/* fgets() includes the trailing newline in the output buffer, /* getline() may include the trailing newline in the output
* so we need to clean that up ourselves. We can safely access * buffer, so we need to clean that up ourselves. */
* line[strlen(line) - 1] because the checks above would cause virStringTrimOptionalNewline(line);
* us to skip empty strings */
line[strlen(line) - 1] = '\0';
/* Skip to the separator */ /* Skip to the separator */
if (!(start = strchr(line, ':'))) if (!(start = strchr(line, ':')))
@ -153,7 +149,7 @@ virBitmap *virHostValidateGetCPUFlags(void)
if ((value = virHostValidateCPUFlagTypeFromString(*next)) >= 0) if ((value = virHostValidateCPUFlagTypeFromString(*next)) >= 0)
ignore_value(virBitmapSetBit(flags, value)); ignore_value(virBitmapSetBit(flags, value));
} }
} while (1); }
VIR_FORCE_FCLOSE(fp); VIR_FORCE_FCLOSE(fp);