1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
From: Marc Haber <mh+debian-packages@zugschlus.de>
Date: Sun, 25 May 2025 21:05:56 +0200
Subject: fix buffer overflow crash on Raspberry Pi 5 (fake NUMA architecture)
Closes: #1106234
Thanks: Gerlof Langeveld
Author: Gerlof Langeveld
Forwarded: not-needed
---
photosyst.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
photosyst.h | 1 +
showlinux.c | 12 ++++++++----
3 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/photosyst.c b/photosyst.c
index 2f862fd..5670393 100644
--- a/photosyst.c
+++ b/photosyst.c
@@ -2646,6 +2646,57 @@ get_ksm(struct sstat *si)
}
+/*
+** determine if this system uses *real* NUMA rather than *fake* NUMA
+** that is the case when not all node distances have the same value
+*/
+#define NUMADISTANCE0 "/sys/devices/system/node/node0/distance"
+
+int
+uses_realnuma(void)
+{
+ static int realnuma = -1;
+ FILE *fp;
+ int i, total, nr=0, dist[10];
+ char linebuf[1024];
+
+ if (realnuma == -1) // first call?
+ {
+ if ( (fp = fopen(NUMADISTANCE0, "r")) != NULL)
+ {
+ if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
+ {
+ nr = sscanf(linebuf, "%d %d %d %d %d %d %d %d %d %d",
+ &dist[0], &dist[1], &dist[2], &dist[3],
+ &dist[4], &dist[5], &dist[6], &dist[7],
+ &dist[8], &dist[9]);
+ }
+
+ fclose(fp);
+ }
+
+ if (nr <= 0)
+ {
+ realnuma = 0; // probably fake NUMA
+ }
+ else
+ {
+ // totalize all distances
+ for (i=0, total=0; i < nr; i++)
+ total += dist[i];
+
+ // average distance not equal to the first distance?
+ if (total / i != dist[0])
+ realnuma = 1; // real NUMA
+ else
+ realnuma = 0; // fake NUMA
+ }
+ }
+
+ return realnuma;
+}
+
+
#if HTTPSTATS
/*
** retrieve statistics from local HTTP daemons
diff --git a/photosyst.h b/photosyst.h
index 600fb36..ebe4115 100644
--- a/photosyst.h
+++ b/photosyst.h
@@ -468,6 +468,7 @@ void deviatsyst(struct sstat *, struct sstat *, struct sstat *, long);
void totalsyst (char, struct sstat *, struct sstat *);
void do_perfevents(char *, char *);
int isdisk_major(unsigned int);
+int uses_realnuma(void);
/*
** return value of isdisk_...()
diff --git a/showlinux.c b/showlinux.c
index 3bdf804..817e967 100644
--- a/showlinux.c
+++ b/showlinux.c
@@ -1969,7 +1969,7 @@ prisyst(struct sstat *sstat, int curline, int nsecs, int avgval,
/*
** memory info related for per NUMA
*/
- if (sstat->memnuma.nrnuma > 1)
+ if (sstat->memnuma.nrnuma > 1 && uses_realnuma())
{
for (extra.index=lin=0;
extra.index < sstat->memnuma.nrnuma && lin < maxnumalines;
@@ -2005,7 +2005,7 @@ prisyst(struct sstat *sstat, int curline, int nsecs, int avgval,
/*
** Accumulate each cpu statistic for per NUMA
*/
- if (sstat->cpunuma.nrnuma > 1)
+ if (sstat->cpunuma.nrnuma > 1 && uses_realnuma())
{
for (extra.index=lin=0;
extra.index < sstat->cpunuma.nrnuma && lin < maxnumalines;
@@ -2045,8 +2045,12 @@ prisyst(struct sstat *sstat, int curline, int nsecs, int avgval,
*highorderp = MSORTCPU;
}
- extra.percputot = extra.pernumacputot /
- (sstat->cpu.nrcpu/sstat->cpunuma.nrnuma);
+ if (sstat->cpunuma.numa[extra.index].nrcpu)
+ extra.percputot = extra.pernumacputot /
+ sstat->cpunuma.numa[extra.index].nrcpu;
+ else
+ extra.percputot = 1;
+
if (extra.percputot == 0)
extra.percputot = 1; /* avoid divide-by-zero */
|