36e8a3
From 886e5b028953404f2d924b561c0689d3e50dbbf4 Mon Sep 17 00:00:00 2001
36e8a3
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
36e8a3
Date: Thu, 13 Sep 2018 09:24:36 +0200
36e8a3
Subject: [PATCH] detect-virt: do not try to read all of /proc/cpuinfo
36e8a3
36e8a3
Quoting https://github.com/systemd/systemd/issues/10074:
36e8a3
> detect_vm_uml() reads /proc/cpuinfo with read_full_file()
36e8a3
> read_full_file() has a file max limit size of READ_FULL_BYTES_MAX=(4U*1024U*1024U)
36e8a3
> Unfortunately, the size of my /proc/cpuinfo is bigger, approximately:
36e8a3
> echo $(( 4* $(cat /proc/cpuinfo | wc -c)))
36e8a3
> 9918072
36e8a3
> This causes read_full_file() to fail and the Condition test fallout.
36e8a3
36e8a3
Let's just read line by line until we find an intersting line. This also
36e8a3
helps if not running under UML, because we avoid reading as much data.
36e8a3
36e8a3
(cherry picked from commit 6058516a14ada1748313af6783f5b4e7e3006654)
36e8a3
36e8a3
Resolves: #1631532
36e8a3
---
36e8a3
 src/basic/virt.c | 38 ++++++++++++++++++++++++++++----------
36e8a3
 1 file changed, 28 insertions(+), 10 deletions(-)
36e8a3
36e8a3
diff --git a/src/basic/virt.c b/src/basic/virt.c
4bff0a
index d347732bb3..e05b3e6d99 100644
36e8a3
--- a/src/basic/virt.c
36e8a3
+++ b/src/basic/virt.c
36e8a3
@@ -11,6 +11,7 @@
36e8a3
 
36e8a3
 #include "alloc-util.h"
36e8a3
 #include "dirent-util.h"
36e8a3
+#include "def.h"
36e8a3
 #include "env-util.h"
36e8a3
 #include "fd-util.h"
36e8a3
 #include "fileio.h"
36e8a3
@@ -259,21 +260,38 @@ static int detect_vm_hypervisor(void) {
36e8a3
 }
36e8a3
 
36e8a3
 static int detect_vm_uml(void) {
36e8a3
-        _cleanup_free_ char *cpuinfo_contents = NULL;
36e8a3
+        _cleanup_fclose_ FILE *f = NULL;
36e8a3
         int r;
36e8a3
 
36e8a3
         /* Detect User-Mode Linux by reading /proc/cpuinfo */
36e8a3
-        r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
36e8a3
-        if (r == -ENOENT) {
36e8a3
-                log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
36e8a3
-                return VIRTUALIZATION_NONE;
36e8a3
+        f = fopen("/proc/cpuinfo", "re");
36e8a3
+        if (!f) {
36e8a3
+                if (errno == ENOENT) {
36e8a3
+                        log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
36e8a3
+                        return VIRTUALIZATION_NONE;
36e8a3
+                }
36e8a3
+                return -errno;
36e8a3
         }
36e8a3
-        if (r < 0)
36e8a3
-                return r;
36e8a3
 
36e8a3
-        if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
36e8a3
-                log_debug("UML virtualization found in /proc/cpuinfo");
36e8a3
-                return VIRTUALIZATION_UML;
36e8a3
+        for (;;) {
36e8a3
+                _cleanup_free_ char *line = NULL;
36e8a3
+                const char *t;
36e8a3
+
36e8a3
+                r = read_line(f, LONG_LINE_MAX, &line);
36e8a3
+                if (r < 0)
36e8a3
+                        return r;
36e8a3
+                if (r == 0)
36e8a3
+                        break;
36e8a3
+
36e8a3
+                t = startswith(line, "vendor_id\t: ");
36e8a3
+                if (t) {
36e8a3
+                        if (startswith(t, "User Mode Linux")) {
36e8a3
+                                log_debug("UML virtualization found in /proc/cpuinfo");
36e8a3
+                                return VIRTUALIZATION_UML;
36e8a3
+                        }
36e8a3
+
36e8a3
+                        break;
36e8a3
+                }
36e8a3
         }
36e8a3
 
36e8a3
         log_debug("UML virtualization not found in /proc/cpuinfo.");