Blob Blame History Raw
From eb8660e2aae2f0366886e73dc37beb236e89188b Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 16 Nov 2023 14:22:15 +0200
Subject: [PATCH 2/2] Fix integer overflow in memory calculations on 32bit
 systems

"long int" on at least x86 Linux is exactly the same as a plain "int",
so calculations can easily overflow. 32bit systems are not expected to
have hundreds of gigabytes of memory but a 32bit process on a x86_64 can
run into all sorts of funny things, such having 500GB system memory. At
which point the type capable of addressing all of process memory is
absolutely useless for calculating the total memory.

Use uint64_t in the memory calculations to make the size explicit. Of course
one day we may cross that border too, but I hope to be retired by then.

Fixes https://issues.redhat.com/browse/RHEL-16557
---
 rpmio/macro.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/rpmio/macro.c b/rpmio/macro.c
index 98067442555f7c458ea4976d96b5438db01bd031..354b06b0ed34c030638788da5d397b7ba108e806 100644
--- a/rpmio/macro.c
+++ b/rpmio/macro.c
@@ -1177,30 +1177,32 @@ static void doShescape(MacroBuf mb, rpmMacroEntry me, ARGV_t argv, size_t *parse
     mbAppend(mb, '\'');
 }
 
-static unsigned long getmem_total(void)
+static uint64_t getmem_total(void)
 {
-    unsigned long mem = 0;
+    uint64_t mem = 0;
     long int pagesize = sysconf(_SC_PAGESIZE);
     long int pages = sysconf(_SC_PHYS_PAGES);
 
-    if (pagesize < 0)
+    if (pagesize <= 0)
 	pagesize = 4096;
-    if (pages > 0)
-	mem = pages * pagesize;
+    if (pages > 0) {
+	/* Cast needed to force 64bit calculation on 32bit systems */
+	mem = (uint64_t)pages * pagesize;
+    }
 
     return mem;
 }
 
-static unsigned long getmem_proc(int thread)
+static uint64_t getmem_proc(int thread)
 {
-    unsigned long mem = getmem_total();
+    uint64_t mem = getmem_total();
     /*
      * Conservative estimates for thread use on 32bit systems where address
      * space is an issue: 2GB for bare metal, 3GB for a 32bit process
      * on a 64bit system.
      */
     if (thread) {
-	unsigned long vmem = mem;
+	uint64_t vmem = mem;
 #if __WORDSIZE == 32
 	vmem = UINT32_MAX / 2;
 #else
@@ -1224,7 +1226,7 @@ static void doGetncpus(MacroBuf mb, rpmMacroEntry me, ARGV_t argv, size_t *parse
     const char *arg = argv[1] ? argv[1] : "total";
     char buf[32];
     unsigned int ncpus = getncpus();
-    unsigned long mem = 0;
+    uint64_t mem = 0;
 
     if (rstreq(arg, "total")) {
 	/* nothing */
-- 
2.43.0