Details: https://nvd.nist.gov/vuln/detail/CVE-2025-31160

Backport the patch that's subject references the CVE id explicitly.

I was able to verify the patch with a reproducer[1] (which is mentioned
in a reference[2] in the nvd report). Without the patch atop crashed,
with the patch it worked fine (both with and without -k/-K flags).

[1]: https://blog.bismuth.sh/blog/bismuth-found-the-atop-bug
[2]: https://gist.github.com/kallsyms/3acdf857ccc5c9fbaae7ed823be0365e

Signed-off-by: Gyorgy Sarvari <[email protected]>
---
 .../atop/atop/CVE-2025-31160.patch            | 607 ++++++++++++++++++
 meta-oe/recipes-support/atop/atop_2.4.0.bb    |   1 +
 2 files changed, 608 insertions(+)
 create mode 100644 meta-oe/recipes-support/atop/atop/CVE-2025-31160.patch

diff --git a/meta-oe/recipes-support/atop/atop/CVE-2025-31160.patch 
b/meta-oe/recipes-support/atop/atop/CVE-2025-31160.patch
new file mode 100644
index 0000000000..d83eca13ef
--- /dev/null
+++ b/meta-oe/recipes-support/atop/atop/CVE-2025-31160.patch
@@ -0,0 +1,607 @@
+From 6427a26127cfec800b7064fd8700837c9f0c3548 Mon Sep 17 00:00:00 2001
+From: Gerlof Langeveld <[email protected]>
+Date: Sat, 29 Mar 2025 18:56:44 +0100
+Subject: [PATCH] Fix security vulnerability CVE-2025-31160 (#334)
+
+Atop will not connect to the TCP port of 'atopgpud' daemon any more
+by default.  The flag -k can be used explicitly when 'atopgpud' is
+active. Also the code to parse the received strings is improved to
+avoid future issues with heap corruption.
+
+The flag -K has been implemented to connect to netatop/netatop-bpf.
+CVE: CVE-2025-31160
+Upstream-Status: Backport 
[https://github.com/Atoptool/atop/commit/ec8f3038497fcf493c6ff9c9f98f7a7c6216a1cb]
+Signed-off-by: Gyorgy Sarvari <[email protected]>
+---
+ atop.c      |  59 +++++++--------
+ atop.h      |   1 +
+ gpucom.c    | 210 +++++++++++++++++++++++++++++++++++++---------------
+ photoproc.c |   3 +-
+ 4 files changed, 182 insertions(+), 91 deletions(-)
+
+diff --git a/atop.c b/atop.c
+index 7ea9cc8..967df46 100644
+--- a/atop.c
++++ b/atop.c
+@@ -333,6 +333,8 @@ int                ossub;
+ int           supportflags;   /* supported features                   */
+ char          **argvp;
+ 
++char          connectgpud     = 0; /* boolean: connect to atopgpud      */
++char          connectnetatop  = 0; /* boolean: connect to netatop(bpf)  */
+ 
+ struct visualize vis = {generic_samp, generic_error,
+                       generic_end,  generic_usage};
+@@ -573,7 +575,12 @@ main(int argc, char *argv[])
+ 
+                               linelen = atoi(optarg);
+                               break;
+-
++                           case 'k':          /* try to open TCP connection 
to atopgpud */
++                                connectgpud = 1;
++                                break;
++                           case 'K':          /* try to open connection to 
netatop/netatop-bpf */
++                                connectnetatop = 1;
++                                break;
+                          default:             /* gather other flags */
+                               flaglist[i++] = c;
+                       }
+@@ -688,7 +695,8 @@ main(int argc, char *argv[])
+       /*
+       ** open socket to the IP layer to issue getsockopt() calls later on
+       */
+-      netatop_ipopen();
++      if (connectnetatop)
++              netatop_ipopen();
+ 
+       /*
+       ** since privileged activities are finished now, there is no
+@@ -791,11 +799,15 @@ engine(void)
+ 
+       /*
+       ** open socket to the atopgpud daemon for GPU statistics
++      ** if explicitly required
+       */
+-        nrgpus = gpud_init();
++      if (connectgpud)
++      {
++              nrgpus = gpud_init();
+ 
+-      if (nrgpus)
+-              supportflags |= GPUSTAT;
++              if (nrgpus)
++                      supportflags |= GPUSTAT;
++      }
+ 
+       /*
+       ** MAIN-LOOP:
+@@ -842,7 +854,10 @@ engine(void)
+               ** send request for statistics to atopgpud 
+               */
+               if (nrgpus)
+-                      gpupending = gpud_statrequest();
++              {
++                      if ((gpupending = gpud_statrequest()) == 0)
++                              nrgpus = 0;
++              }
+ 
+               /*
+               ** take a snapshot of the current system-level statistics 
+@@ -867,28 +882,8 @@ engine(void)
+                       // connection lost or timeout on receive?
+                       if (nrgpuproc == -1)
+                       {
+-                              int ng;
+-
+-                              // try to reconnect
+-                              ng = gpud_init();
+-
+-                              if (ng != nrgpus)       // no success
+-                                      nrgpus = 0;
+-
+-                              if (nrgpus)
+-                              {
+-                                      // request for stats again
+-                                      if (gpud_statrequest())
+-                                      {
+-                                              // receive stats response
+-                                              nrgpuproc = 
gpud_statresponse(nrgpus,
+-                                                   cursstat->gpu.gpu, &gp);
+-
+-                                              // persistent failure?
+-                                              if (nrgpuproc == -1)
+-                                                      nrgpus = 0;
+-                                      }
+-                              }
++                              nrgpus = 0;
++                              supportflags &= ~GPUSTAT;
+                       }
+ 
+                       cursstat->gpu.nrgpus = nrgpus;
+@@ -977,7 +972,7 @@ engine(void)
+               /*
+               ** merge GPU per-process stats with other per-process stats
+               */
+-              if (nrgpus && nrgpuproc)
++              if (nrgpus && nrgpuproc > 0)
+                       gpumergeproc(curtpres, ntaskpres,
+                                    curpexit, nprocexit,
+                                    gp,       nrgpuproc);
+@@ -1008,8 +1003,8 @@ engine(void)
+               if (nprocexitnet > 0)
+                       netatop_exiterase();
+ 
+-              if (gp)
+-                       free(gp);
++              free(gp);
++              gp = NULL;      // avoid double free
+ 
+               if (lastcmd == 'r')     /* reset requested ? */
+               {
+@@ -1050,6 +1045,8 @@ prusage(char *myname)
+       printf("\t  -P  generate parseable output for specified label(s)\n");
+       printf("\t  -L  alternate line length (default 80) in case of "
+                       "non-screen output\n");
++      printf("\t  -k  try to connect to external atopgpud daemon (default: do 
not connect)\n");
++      printf("\t  -K  try to connect to netatop/netatop-bpf interface 
(default: do not connect)\n");
+ 
+       (*vis.show_usage)();
+ 
+diff --git a/atop.h b/atop.h
+index 791c450..cbf4225 100644
+--- a/atop.h
++++ b/atop.h
+@@ -82,6 +82,7 @@ extern char          threadview;
+ extern char           calcpss;
+ extern char           rawname[];
+ extern char           rawreadflag;
++extern char           connectnetatop;
+ extern unsigned int   begintime, endtime;
+ extern char           flaglist[];
+ extern struct visualize vis;
+diff --git a/gpucom.c b/gpucom.c
+index 4834851..690937e 100644
+--- a/gpucom.c
++++ b/gpucom.c
+@@ -43,12 +43,12 @@
+ 
+ #define       GPUDPORT        59123
+ 
+-static void   gputype_parse(char *);
++static int    gputype_parse(char *);
+ 
+-static void   gpustat_parse(int, char *, int,
++static int    gpustat_parse(int, char *, int,
+                                     struct pergpu *, struct gpupidstat *);
+-static void   gpuparse(int, char *, struct pergpu *);
+-static void   pidparse(int, char *, struct gpupidstat *);
++static int    gpuparse(int, char *, struct pergpu *);
++static int    pidparse(int, char *, struct gpupidstat *);
+ static int    rcvuntil(int, char *, int);
+ 
+ static int    actsock = -1;
+@@ -150,20 +150,24 @@ gpud_init(void)
+       if ( rcvuntil(actsock, buf, length) == -1)
+       {
+               perror("receive type request from atopgpud");
++              free(buf);
+               goto close_and_return;
+       }
+ 
+       buf[length] = '\0';
+ 
+-      gputype_parse(buf);
+-
+-        numgpus = numgpus <= MAXGPU ? numgpus : MAXGPU;
++      if (! gputype_parse(buf))
++      {
++              free(buf);
++              goto close_and_return;
++      }
+ 
+       return numgpus;
+ 
+     close_and_return:
+       close(actsock);
+       actsock = -1;
++      numgpus = 0;
+       return 0;
+ }
+ 
+@@ -176,7 +180,7 @@ gpud_init(void)
+ **
+ ** Return value:
+ **    0 in case of failure
+-**    1 in case of success
++**    1 in case of success (request pending)
+ */
+ int
+ gpud_statrequest(void)
+@@ -190,6 +194,7 @@ gpud_statrequest(void)
+       {
+               close(actsock);
+               actsock = -1;
++              numgpus = 0;
+               return 0;
+       }
+ 
+@@ -216,7 +221,7 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct 
gpupidstat **gps)
+       uint32_t        prelude;
+       char            *buf = NULL, *p;
+       int             version, length;
+-      int             pids = 0;
++      int             maxprocs = 0, nrprocs;
+ 
+       if (actsock == -1)
+               return -1;
+@@ -269,22 +274,22 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct 
gpupidstat **gps)
+       *(buf+length) = '\0';
+ 
+       /*
+-      ** determine number of per-process stats
+-      ** and malloc space to parse these stats
++      ** determine number of per-process stats in string
++      ** and malloc space to store these stats
+       */
+       for (p=buf; *p; p++)
+       {
+               if (*p == PIDDELIM)
+-                      pids++;
++                      maxprocs++;
+       }
+ 
+       if (gps)
+       {
+-              if (pids)
++              if (maxprocs)
+               {
+-                      *gps = malloc(pids * sizeof(struct gpupidstat));
+-                      ptrverify(gps, "Malloc failed for gpu pidstats\n");
+-                      memset(*gps, 0, pids * sizeof(struct gpupidstat));
++                      *gps = malloc(maxprocs * sizeof(struct gpupidstat));
++                      ptrverify(*gps, "Malloc failed for gpu pidstats\n");
++                      memset(*gps, 0, maxprocs * sizeof(struct gpupidstat));
+               }
+               else
+               {
+@@ -295,18 +300,27 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct 
gpupidstat **gps)
+       /*
+       ** parse stats string for per-gpu stats
+       */
+-      gpustat_parse(version, buf, maxgpu, ggs, gps ? *gps : NULL);
++      if ( (nrprocs =  gpustat_parse(version, buf, maxgpu, ggs, gps ? *gps : 
NULL)) == -1)
++      {
++      if (gps)
++              {
++                      free(*gps);
++                      *gps = NULL;    // avoid double free later on
++              }
++
++              goto close_and_return; // inconsistent data received from 
atopgpud
++      }
+ 
+       free(buf);
+ 
+-      return pids;
++      return nrprocs;
+ 
+     close_and_return:
+-      if (buf)
+-              free(buf);
++      free(buf);
+ 
+       close(actsock);
+       actsock = -1;
++      numgpus = 0;
+       return -1;
+ }
+ 
+@@ -314,6 +328,8 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct 
gpupidstat **gps)
+ /*
+ ** Receive given number of bytes from given socket
+ ** into given buffer address
++** Return value:  number of bytes received
++**              -1 - failed (including end-of-connection)
+ */
+ static int
+ rcvuntil(int sock, char *buf, int size)
+@@ -339,21 +355,22 @@ rcvuntil(int sock, char *buf, int size)
+ **
+ ** Store the type, busid and tasksupport of every GPU in
+ ** static pointer tables
++**
++** Return value:  1 - success
++**                0 - failed
+ */
+-static void
++static int
+ gputype_parse(char *buf)
+ {
+-      char    *p, *start, **bp, **tp, *cp;
++      char    *p, *start, **bp, **tp, *cp, fails=0;
+ 
+       /*
+       ** determine number of GPUs
+       */
+       if ( sscanf(buf, "%d@", &numgpus) != 1)
+-      {
+-              close(actsock);
+-              actsock = -1;
+               return;
+-      }
++
++      numgpus = numgpus <= MAXGPU ? numgpus : MAXGPU;
+ 
+       for (p=buf; *p; p++)    // search for first delimiter
+       {
+@@ -364,6 +381,9 @@ gputype_parse(char *buf)
+               }
+       }
+ 
++      if (*p == 0)    // no delimiter or no data behind delimeter?
++              return 0;
++
+       /*
+       ** parse GPU info and build arrays of pointers to the
+       ** busid strings, type strings and tasksupport strings.
+@@ -380,27 +400,47 @@ gputype_parse(char *buf)
+               ptrverify(gputypes, "Malloc failed for gpu types\n");
+               ptrverify(gputasks, "Malloc failed for gpu tasksup\n");
+ 
+-              for (field=0, start=p; ; p++)
++              for (field=0, start=p; fails == 0; p++)
+               {
+                       if (*p == ' ' || *p == '\0' || *p == GPUDELIM)
+                       {
+                               switch(field)
+                               {
+                                  case 0:
++                                      if (bp - gpubusid >= numgpus)
++                                      {
++                                              fails++;
++                                              break;  // inconsistent with 
number of GPUs
++                                      }
++
+                                       if (p-start <= MAXGPUBUS)
+                                               *bp++ = start;
+                                       else
+                                               *bp++ = p - MAXGPUBUS;
+                                       break;
+                                  case 1:
++                                      if (tp - gputypes >= numgpus)
++                                      {
++                                              fails++;
++                                              break;  // inconsistent with 
number of GPUs
++                                      }
++
+                                       if (p-start <= MAXGPUTYPE)
+                                               *tp++ = start;
+                                       else
+                                               *tp++ = p - MAXGPUTYPE;
+                                       break;
+                                  case 2:
++                                      if (cp - gputasks >= numgpus)
++                                      {
++                                              fails++;
++                                              break;  // inconsistent with 
number of GPUs
++                                      }
++
+                                       *cp++ = *start;
+                                       break;
++                                 default:
++                                      fails++;
+                               }
+ 
+                               field++;
+@@ -418,7 +458,24 @@ gputype_parse(char *buf)
+ 
+               *bp = NULL;
+               *tp = NULL;
++              /*
++              ** verify if number of GPUs and supplied per-GPU information
++              ** appears to be inconsistent
++              */
++              if (fails || bp - gpubusid != numgpus || tp - gputypes != 
numgpus || cp - gputasks != numgpus)
++              {
++                      free(gpubusid);
++                      free(gputypes);
++                      free(gputasks);
++                      return 0;
++              }
++      }
++      else
++      {
++              return 0;
+       }
++
++      return 1;
+ }
+ 
+ 
+@@ -430,105 +487,140 @@ gputype_parse(char *buf)
+ ** Every series with counters on process level is introduced
+ ** with a '#' delimiter (last part of the GPU level data).
+ */
+-static void
++static int
+ gpustat_parse(int version, char *buf, int maxgpu, 
+               struct pergpu *gg, struct gpupidstat *gp)
+ {
+-      char    *p, *start, delimlast;
+-      int     gpunum = 0;
++      char    *p, *pp, *start;
++      int     gpunum, nrprocs = 0;
+ 
+       /*
+       ** parse stats string
+       */
+-      for (p=start=buf, delimlast=DUMMY; gpunum <= maxgpu; p++)
++      for (p=buf; *p && *p != GPUDELIM; p++)  // find first GPU deimiter
++              ; 
++
++      if (*p == 0)    // string without GPU delimiter
++              return -1;
++
++      for (p++, start=p, gpunum=0; gpunum < maxgpu; p++)
+       {
+-              char delimnow;
++              char delimnext;
+ 
+-              if (*p != '\0' && *p != GPUDELIM && *p != PIDDELIM)
++              // search next GPU delimiter
++              //
++              if (*p && *p != GPUDELIM)
+                       continue;
+ 
+               /*
+-              ** next delimiter or end-of-string found
++              ** next GPU delimiter or end-of-string found
+               */
+-              delimnow = *p;
++              delimnext = *p;
+               *p       = 0;
+ 
+-              switch (delimlast)
+-              {
+-                 case DUMMY:
+-                      break;
+-
+-                 case GPUDELIM:
+-                      gpuparse(version, start, gg);
+-
+-                      strcpy(gg->type,  gputypes[gpunum]);
+-                      strcpy(gg->busid, gpubusid[gpunum]);
++              /*
++              ** parse GPU itself
++              */
++              if (! gpuparse(version, start, gg))
++                      return -1;
+ 
+-                      gpunum++;
+-                      gg++;
+-                      break;
++              strncpy(gg->type,  gputypes[gpunum], MAXGPUTYPE);
++              strncpy(gg->busid, gpubusid[gpunum], MAXGPUBUS);
+ 
+-                 case PIDDELIM:
+-                      if (gp)
++              /*
++              ** continue searching for per-process stats for this GPU
++              */
++              if (gp)
++              {
++                      for (pp = start; pp < p; pp++)
+                       {
+-                              pidparse(version, start, gp);
++                              if (*pp != PIDDELIM)
++                                      continue;
++
++                              // new PID delimiter (#) found
++                              //
++                              if (! pidparse(version, pp+1, gp))
++                                      return -1;
+ 
+                               gp->gpu.nrgpus++;
+-                              gp->gpu.gpulist = 1<<(gpunum-1);
++                              gp->gpu.gpulist = 1<<gpunum;
+                               gp++;
+ 
+-                              (gg-1)->nrprocs++;
++                              gg->nrprocs++;  // per GPU
++                              nrprocs++;      // total
+                       }
+               }
+ 
+-              if (delimnow == 0 || *(p+1) == 0)
++              gpunum++;
++              gg++;
++
++              if (delimnext == 0 || *(p+1) == 0)
+                       break;
+ 
+               start     = p+1;
+-              delimlast = delimnow;
+       }
++      return nrprocs;
+ }
+ 
+ 
+ /*
+ ** Parse GPU statistics string
++** Return value:  1 - success
++**                0 - failed 
+ */
+-static void
++static int
+ gpuparse(int version, char *p, struct pergpu *gg)
+ {
++      int nr;
++
+       switch (version)
+       {
+          case 1:
+-              (void) sscanf(p, "%d %d %lld %lld %lld %lld %lld %lld", 
++              nr = sscanf(p, "%d %d %lld %lld %lld %lld %lld %lld",
+                       &(gg->gpupercnow), &(gg->mempercnow),
+                       &(gg->memtotnow),  &(gg->memusenow),
+                       &(gg->samples),    &(gg->gpuperccum),
+                       &(gg->memperccum), &(gg->memusecum));
+ 
++              if (nr < 8)     // parse error: unexpected data
++                      return 0;
++
+               gg->nrprocs = 0;
+ 
+               break;
+       }
++
++      return 1;
+ }
+ 
+ 
+ /*
+ ** Parse PID statistics string
++** Return value:  1 - success
++**                0 - failed
+ */
+-static void
++static int
+ pidparse(int version, char *p, struct gpupidstat *gp)
+ {
++      int nr;
++
+       switch (version)
+       {
+          case 1:
+-              (void) sscanf(p, "%c %ld %d %d %lld %lld %lld %lld",
++              nr = sscanf(p, "%c %ld %d %d %lld %lld %lld %lld",
+                       &(gp->gpu.state),   &(gp->pid),    
+                       &(gp->gpu.gpubusy), &(gp->gpu.membusy),
+                       &(gp->gpu.timems),
+                       &(gp->gpu.memnow), &(gp->gpu.memcum),
+                       &(gp->gpu.sample));
++
++              if (nr < 8)     // parse error: unexpected data
++                      return 0;
++
+               break;
+       }
++
++      return 1;
+ }
+ 
+ 
+diff --git a/photoproc.c b/photoproc.c
+index e5cd88b..5df04e3 100644
+--- a/photoproc.c
++++ b/photoproc.c
+@@ -216,7 +216,8 @@ photoproc(struct tstat *tasklist, int maxtask)
+       */
+       regainrootprivs();
+ 
+-      netatop_probe();
++      if (connectnetatop)
++              netatop_probe();
+ 
+       if (! droprootprivs())
+               cleanstop(42);
diff --git a/meta-oe/recipes-support/atop/atop_2.4.0.bb 
b/meta-oe/recipes-support/atop/atop_2.4.0.bb
index b1d2abde73..e244b3e31d 100644
--- a/meta-oe/recipes-support/atop/atop_2.4.0.bb
+++ b/meta-oe/recipes-support/atop/atop_2.4.0.bb
@@ -20,6 +20,7 @@ SRC_URI = "http://www.atoptool.nl/download/${BP}.tar.gz \
            file://fix-permissions.patch \
            file://sysvinit-implement-status.patch \
            file://0001-atop.daily-atop.init-atop-pm.sh-Avoid-using-bash.patch \
+           file://CVE-2025-31160.patch \
            "
 SRC_URI[md5sum] = "1077da884ed94f2bc3c81ac3ab970436"
 SRC_URI[sha256sum] = 
"be1c010a77086b7d98376fce96514afcd73c3f20a8d1fe01520899ff69a73d69"
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#123000): 
https://lists.openembedded.org/g/openembedded-devel/message/123000
Mute This Topic: https://lists.openembedded.org/mt/116989654/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to