summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGyorgy Sarvari <skandigraun@gmail.com>2025-12-29 21:54:12 +0100
committerAnuj Mittal <anuj.mittal@oss.qualcomm.com>2025-12-30 07:08:16 +0530
commit2b26d30fc7f478f5735d514f0c1bc28f6a4148b6 (patch)
treeb62b37d462a8b3334b9f2f76b99dc93a3cac908f
parent02dbaa8843c04acae47e7a950c0d48871e5958e7 (diff)
downloadmeta-openembedded-2b26d30fc7f478f5735d514f0c1bc28f6a4148b6.tar.gz
atop: patch CVE-2025-31160
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 <skandigraun@gmail.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
-rw-r--r--meta-oe/recipes-support/atop/atop/CVE-2025-31160.patch607
-rw-r--r--meta-oe/recipes-support/atop/atop_2.4.0.bb1
2 files changed, 608 insertions, 0 deletions
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 @@
1From 6427a26127cfec800b7064fd8700837c9f0c3548 Mon Sep 17 00:00:00 2001
2From: Gerlof Langeveld <gerlof.langeveld@atoptool.nl>
3Date: Sat, 29 Mar 2025 18:56:44 +0100
4Subject: [PATCH] Fix security vulnerability CVE-2025-31160 (#334)
5
6Atop will not connect to the TCP port of 'atopgpud' daemon any more
7by default. The flag -k can be used explicitly when 'atopgpud' is
8active. Also the code to parse the received strings is improved to
9avoid future issues with heap corruption.
10
11The flag -K has been implemented to connect to netatop/netatop-bpf.
12CVE: CVE-2025-31160
13Upstream-Status: Backport [https://github.com/Atoptool/atop/commit/ec8f3038497fcf493c6ff9c9f98f7a7c6216a1cb]
14Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
15---
16 atop.c | 59 +++++++--------
17 atop.h | 1 +
18 gpucom.c | 210 +++++++++++++++++++++++++++++++++++++---------------
19 photoproc.c | 3 +-
20 4 files changed, 182 insertions(+), 91 deletions(-)
21
22diff --git a/atop.c b/atop.c
23index 7ea9cc8..967df46 100644
24--- a/atop.c
25+++ b/atop.c
26@@ -333,6 +333,8 @@ int ossub;
27 int supportflags; /* supported features */
28 char **argvp;
29
30+char connectgpud = 0; /* boolean: connect to atopgpud */
31+char connectnetatop = 0; /* boolean: connect to netatop(bpf) */
32
33 struct visualize vis = {generic_samp, generic_error,
34 generic_end, generic_usage};
35@@ -573,7 +575,12 @@ main(int argc, char *argv[])
36
37 linelen = atoi(optarg);
38 break;
39-
40+ case 'k': /* try to open TCP connection to atopgpud */
41+ connectgpud = 1;
42+ break;
43+ case 'K': /* try to open connection to netatop/netatop-bpf */
44+ connectnetatop = 1;
45+ break;
46 default: /* gather other flags */
47 flaglist[i++] = c;
48 }
49@@ -688,7 +695,8 @@ main(int argc, char *argv[])
50 /*
51 ** open socket to the IP layer to issue getsockopt() calls later on
52 */
53- netatop_ipopen();
54+ if (connectnetatop)
55+ netatop_ipopen();
56
57 /*
58 ** since privileged activities are finished now, there is no
59@@ -791,11 +799,15 @@ engine(void)
60
61 /*
62 ** open socket to the atopgpud daemon for GPU statistics
63+ ** if explicitly required
64 */
65- nrgpus = gpud_init();
66+ if (connectgpud)
67+ {
68+ nrgpus = gpud_init();
69
70- if (nrgpus)
71- supportflags |= GPUSTAT;
72+ if (nrgpus)
73+ supportflags |= GPUSTAT;
74+ }
75
76 /*
77 ** MAIN-LOOP:
78@@ -842,7 +854,10 @@ engine(void)
79 ** send request for statistics to atopgpud
80 */
81 if (nrgpus)
82- gpupending = gpud_statrequest();
83+ {
84+ if ((gpupending = gpud_statrequest()) == 0)
85+ nrgpus = 0;
86+ }
87
88 /*
89 ** take a snapshot of the current system-level statistics
90@@ -867,28 +882,8 @@ engine(void)
91 // connection lost or timeout on receive?
92 if (nrgpuproc == -1)
93 {
94- int ng;
95-
96- // try to reconnect
97- ng = gpud_init();
98-
99- if (ng != nrgpus) // no success
100- nrgpus = 0;
101-
102- if (nrgpus)
103- {
104- // request for stats again
105- if (gpud_statrequest())
106- {
107- // receive stats response
108- nrgpuproc = gpud_statresponse(nrgpus,
109- cursstat->gpu.gpu, &gp);
110-
111- // persistent failure?
112- if (nrgpuproc == -1)
113- nrgpus = 0;
114- }
115- }
116+ nrgpus = 0;
117+ supportflags &= ~GPUSTAT;
118 }
119
120 cursstat->gpu.nrgpus = nrgpus;
121@@ -977,7 +972,7 @@ engine(void)
122 /*
123 ** merge GPU per-process stats with other per-process stats
124 */
125- if (nrgpus && nrgpuproc)
126+ if (nrgpus && nrgpuproc > 0)
127 gpumergeproc(curtpres, ntaskpres,
128 curpexit, nprocexit,
129 gp, nrgpuproc);
130@@ -1008,8 +1003,8 @@ engine(void)
131 if (nprocexitnet > 0)
132 netatop_exiterase();
133
134- if (gp)
135- free(gp);
136+ free(gp);
137+ gp = NULL; // avoid double free
138
139 if (lastcmd == 'r') /* reset requested ? */
140 {
141@@ -1050,6 +1045,8 @@ prusage(char *myname)
142 printf("\t -P generate parseable output for specified label(s)\n");
143 printf("\t -L alternate line length (default 80) in case of "
144 "non-screen output\n");
145+ printf("\t -k try to connect to external atopgpud daemon (default: do not connect)\n");
146+ printf("\t -K try to connect to netatop/netatop-bpf interface (default: do not connect)\n");
147
148 (*vis.show_usage)();
149
150diff --git a/atop.h b/atop.h
151index 791c450..cbf4225 100644
152--- a/atop.h
153+++ b/atop.h
154@@ -82,6 +82,7 @@ extern char threadview;
155 extern char calcpss;
156 extern char rawname[];
157 extern char rawreadflag;
158+extern char connectnetatop;
159 extern unsigned int begintime, endtime;
160 extern char flaglist[];
161 extern struct visualize vis;
162diff --git a/gpucom.c b/gpucom.c
163index 4834851..690937e 100644
164--- a/gpucom.c
165+++ b/gpucom.c
166@@ -43,12 +43,12 @@
167
168 #define GPUDPORT 59123
169
170-static void gputype_parse(char *);
171+static int gputype_parse(char *);
172
173-static void gpustat_parse(int, char *, int,
174+static int gpustat_parse(int, char *, int,
175 struct pergpu *, struct gpupidstat *);
176-static void gpuparse(int, char *, struct pergpu *);
177-static void pidparse(int, char *, struct gpupidstat *);
178+static int gpuparse(int, char *, struct pergpu *);
179+static int pidparse(int, char *, struct gpupidstat *);
180 static int rcvuntil(int, char *, int);
181
182 static int actsock = -1;
183@@ -150,20 +150,24 @@ gpud_init(void)
184 if ( rcvuntil(actsock, buf, length) == -1)
185 {
186 perror("receive type request from atopgpud");
187+ free(buf);
188 goto close_and_return;
189 }
190
191 buf[length] = '\0';
192
193- gputype_parse(buf);
194-
195- numgpus = numgpus <= MAXGPU ? numgpus : MAXGPU;
196+ if (! gputype_parse(buf))
197+ {
198+ free(buf);
199+ goto close_and_return;
200+ }
201
202 return numgpus;
203
204 close_and_return:
205 close(actsock);
206 actsock = -1;
207+ numgpus = 0;
208 return 0;
209 }
210
211@@ -176,7 +180,7 @@ gpud_init(void)
212 **
213 ** Return value:
214 ** 0 in case of failure
215-** 1 in case of success
216+** 1 in case of success (request pending)
217 */
218 int
219 gpud_statrequest(void)
220@@ -190,6 +194,7 @@ gpud_statrequest(void)
221 {
222 close(actsock);
223 actsock = -1;
224+ numgpus = 0;
225 return 0;
226 }
227
228@@ -216,7 +221,7 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct gpupidstat **gps)
229 uint32_t prelude;
230 char *buf = NULL, *p;
231 int version, length;
232- int pids = 0;
233+ int maxprocs = 0, nrprocs;
234
235 if (actsock == -1)
236 return -1;
237@@ -269,22 +274,22 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct gpupidstat **gps)
238 *(buf+length) = '\0';
239
240 /*
241- ** determine number of per-process stats
242- ** and malloc space to parse these stats
243+ ** determine number of per-process stats in string
244+ ** and malloc space to store these stats
245 */
246 for (p=buf; *p; p++)
247 {
248 if (*p == PIDDELIM)
249- pids++;
250+ maxprocs++;
251 }
252
253 if (gps)
254 {
255- if (pids)
256+ if (maxprocs)
257 {
258- *gps = malloc(pids * sizeof(struct gpupidstat));
259- ptrverify(gps, "Malloc failed for gpu pidstats\n");
260- memset(*gps, 0, pids * sizeof(struct gpupidstat));
261+ *gps = malloc(maxprocs * sizeof(struct gpupidstat));
262+ ptrverify(*gps, "Malloc failed for gpu pidstats\n");
263+ memset(*gps, 0, maxprocs * sizeof(struct gpupidstat));
264 }
265 else
266 {
267@@ -295,18 +300,27 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct gpupidstat **gps)
268 /*
269 ** parse stats string for per-gpu stats
270 */
271- gpustat_parse(version, buf, maxgpu, ggs, gps ? *gps : NULL);
272+ if ( (nrprocs = gpustat_parse(version, buf, maxgpu, ggs, gps ? *gps : NULL)) == -1)
273+ {
274+ if (gps)
275+ {
276+ free(*gps);
277+ *gps = NULL; // avoid double free later on
278+ }
279+
280+ goto close_and_return; // inconsistent data received from atopgpud
281+ }
282
283 free(buf);
284
285- return pids;
286+ return nrprocs;
287
288 close_and_return:
289- if (buf)
290- free(buf);
291+ free(buf);
292
293 close(actsock);
294 actsock = -1;
295+ numgpus = 0;
296 return -1;
297 }
298
299@@ -314,6 +328,8 @@ gpud_statresponse(int maxgpu, struct pergpu *ggs, struct gpupidstat **gps)
300 /*
301 ** Receive given number of bytes from given socket
302 ** into given buffer address
303+** Return value: number of bytes received
304+** -1 - failed (including end-of-connection)
305 */
306 static int
307 rcvuntil(int sock, char *buf, int size)
308@@ -339,21 +355,22 @@ rcvuntil(int sock, char *buf, int size)
309 **
310 ** Store the type, busid and tasksupport of every GPU in
311 ** static pointer tables
312+**
313+** Return value: 1 - success
314+** 0 - failed
315 */
316-static void
317+static int
318 gputype_parse(char *buf)
319 {
320- char *p, *start, **bp, **tp, *cp;
321+ char *p, *start, **bp, **tp, *cp, fails=0;
322
323 /*
324 ** determine number of GPUs
325 */
326 if ( sscanf(buf, "%d@", &numgpus) != 1)
327- {
328- close(actsock);
329- actsock = -1;
330 return;
331- }
332+
333+ numgpus = numgpus <= MAXGPU ? numgpus : MAXGPU;
334
335 for (p=buf; *p; p++) // search for first delimiter
336 {
337@@ -364,6 +381,9 @@ gputype_parse(char *buf)
338 }
339 }
340
341+ if (*p == 0) // no delimiter or no data behind delimeter?
342+ return 0;
343+
344 /*
345 ** parse GPU info and build arrays of pointers to the
346 ** busid strings, type strings and tasksupport strings.
347@@ -380,27 +400,47 @@ gputype_parse(char *buf)
348 ptrverify(gputypes, "Malloc failed for gpu types\n");
349 ptrverify(gputasks, "Malloc failed for gpu tasksup\n");
350
351- for (field=0, start=p; ; p++)
352+ for (field=0, start=p; fails == 0; p++)
353 {
354 if (*p == ' ' || *p == '\0' || *p == GPUDELIM)
355 {
356 switch(field)
357 {
358 case 0:
359+ if (bp - gpubusid >= numgpus)
360+ {
361+ fails++;
362+ break; // inconsistent with number of GPUs
363+ }
364+
365 if (p-start <= MAXGPUBUS)
366 *bp++ = start;
367 else
368 *bp++ = p - MAXGPUBUS;
369 break;
370 case 1:
371+ if (tp - gputypes >= numgpus)
372+ {
373+ fails++;
374+ break; // inconsistent with number of GPUs
375+ }
376+
377 if (p-start <= MAXGPUTYPE)
378 *tp++ = start;
379 else
380 *tp++ = p - MAXGPUTYPE;
381 break;
382 case 2:
383+ if (cp - gputasks >= numgpus)
384+ {
385+ fails++;
386+ break; // inconsistent with number of GPUs
387+ }
388+
389 *cp++ = *start;
390 break;
391+ default:
392+ fails++;
393 }
394
395 field++;
396@@ -418,7 +458,24 @@ gputype_parse(char *buf)
397
398 *bp = NULL;
399 *tp = NULL;
400+ /*
401+ ** verify if number of GPUs and supplied per-GPU information
402+ ** appears to be inconsistent
403+ */
404+ if (fails || bp - gpubusid != numgpus || tp - gputypes != numgpus || cp - gputasks != numgpus)
405+ {
406+ free(gpubusid);
407+ free(gputypes);
408+ free(gputasks);
409+ return 0;
410+ }
411+ }
412+ else
413+ {
414+ return 0;
415 }
416+
417+ return 1;
418 }
419
420
421@@ -430,105 +487,140 @@ gputype_parse(char *buf)
422 ** Every series with counters on process level is introduced
423 ** with a '#' delimiter (last part of the GPU level data).
424 */
425-static void
426+static int
427 gpustat_parse(int version, char *buf, int maxgpu,
428 struct pergpu *gg, struct gpupidstat *gp)
429 {
430- char *p, *start, delimlast;
431- int gpunum = 0;
432+ char *p, *pp, *start;
433+ int gpunum, nrprocs = 0;
434
435 /*
436 ** parse stats string
437 */
438- for (p=start=buf, delimlast=DUMMY; gpunum <= maxgpu; p++)
439+ for (p=buf; *p && *p != GPUDELIM; p++) // find first GPU deimiter
440+ ;
441+
442+ if (*p == 0) // string without GPU delimiter
443+ return -1;
444+
445+ for (p++, start=p, gpunum=0; gpunum < maxgpu; p++)
446 {
447- char delimnow;
448+ char delimnext;
449
450- if (*p != '\0' && *p != GPUDELIM && *p != PIDDELIM)
451+ // search next GPU delimiter
452+ //
453+ if (*p && *p != GPUDELIM)
454 continue;
455
456 /*
457- ** next delimiter or end-of-string found
458+ ** next GPU delimiter or end-of-string found
459 */
460- delimnow = *p;
461+ delimnext = *p;
462 *p = 0;
463
464- switch (delimlast)
465- {
466- case DUMMY:
467- break;
468-
469- case GPUDELIM:
470- gpuparse(version, start, gg);
471-
472- strcpy(gg->type, gputypes[gpunum]);
473- strcpy(gg->busid, gpubusid[gpunum]);
474+ /*
475+ ** parse GPU itself
476+ */
477+ if (! gpuparse(version, start, gg))
478+ return -1;
479
480- gpunum++;
481- gg++;
482- break;
483+ strncpy(gg->type, gputypes[gpunum], MAXGPUTYPE);
484+ strncpy(gg->busid, gpubusid[gpunum], MAXGPUBUS);
485
486- case PIDDELIM:
487- if (gp)
488+ /*
489+ ** continue searching for per-process stats for this GPU
490+ */
491+ if (gp)
492+ {
493+ for (pp = start; pp < p; pp++)
494 {
495- pidparse(version, start, gp);
496+ if (*pp != PIDDELIM)
497+ continue;
498+
499+ // new PID delimiter (#) found
500+ //
501+ if (! pidparse(version, pp+1, gp))
502+ return -1;
503
504 gp->gpu.nrgpus++;
505- gp->gpu.gpulist = 1<<(gpunum-1);
506+ gp->gpu.gpulist = 1<<gpunum;
507 gp++;
508
509- (gg-1)->nrprocs++;
510+ gg->nrprocs++; // per GPU
511+ nrprocs++; // total
512 }
513 }
514
515- if (delimnow == 0 || *(p+1) == 0)
516+ gpunum++;
517+ gg++;
518+
519+ if (delimnext == 0 || *(p+1) == 0)
520 break;
521
522 start = p+1;
523- delimlast = delimnow;
524 }
525+ return nrprocs;
526 }
527
528
529 /*
530 ** Parse GPU statistics string
531+** Return value: 1 - success
532+** 0 - failed
533 */
534-static void
535+static int
536 gpuparse(int version, char *p, struct pergpu *gg)
537 {
538+ int nr;
539+
540 switch (version)
541 {
542 case 1:
543- (void) sscanf(p, "%d %d %lld %lld %lld %lld %lld %lld",
544+ nr = sscanf(p, "%d %d %lld %lld %lld %lld %lld %lld",
545 &(gg->gpupercnow), &(gg->mempercnow),
546 &(gg->memtotnow), &(gg->memusenow),
547 &(gg->samples), &(gg->gpuperccum),
548 &(gg->memperccum), &(gg->memusecum));
549
550+ if (nr < 8) // parse error: unexpected data
551+ return 0;
552+
553 gg->nrprocs = 0;
554
555 break;
556 }
557+
558+ return 1;
559 }
560
561
562 /*
563 ** Parse PID statistics string
564+** Return value: 1 - success
565+** 0 - failed
566 */
567-static void
568+static int
569 pidparse(int version, char *p, struct gpupidstat *gp)
570 {
571+ int nr;
572+
573 switch (version)
574 {
575 case 1:
576- (void) sscanf(p, "%c %ld %d %d %lld %lld %lld %lld",
577+ nr = sscanf(p, "%c %ld %d %d %lld %lld %lld %lld",
578 &(gp->gpu.state), &(gp->pid),
579 &(gp->gpu.gpubusy), &(gp->gpu.membusy),
580 &(gp->gpu.timems),
581 &(gp->gpu.memnow), &(gp->gpu.memcum),
582 &(gp->gpu.sample));
583+
584+ if (nr < 8) // parse error: unexpected data
585+ return 0;
586+
587 break;
588 }
589+
590+ return 1;
591 }
592
593
594diff --git a/photoproc.c b/photoproc.c
595index e5cd88b..5df04e3 100644
596--- a/photoproc.c
597+++ b/photoproc.c
598@@ -216,7 +216,8 @@ photoproc(struct tstat *tasklist, int maxtask)
599 */
600 regainrootprivs();
601
602- netatop_probe();
603+ if (connectnetatop)
604+ netatop_probe();
605
606 if (! droprootprivs())
607 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 bb1f53624a..f6db0508f6 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 \
20 file://fix-permissions.patch \ 20 file://fix-permissions.patch \
21 file://sysvinit-implement-status.patch \ 21 file://sysvinit-implement-status.patch \
22 file://0001-atop.daily-atop.init-atop-pm.sh-Avoid-using-bash.patch \ 22 file://0001-atop.daily-atop.init-atop-pm.sh-Avoid-using-bash.patch \
23 file://CVE-2025-31160.patch \
23 " 24 "
24SRC_URI[md5sum] = "1077da884ed94f2bc3c81ac3ab970436" 25SRC_URI[md5sum] = "1077da884ed94f2bc3c81ac3ab970436"
25SRC_URI[sha256sum] = "be1c010a77086b7d98376fce96514afcd73c3f20a8d1fe01520899ff69a73d69" 26SRC_URI[sha256sum] = "be1c010a77086b7d98376fce96514afcd73c3f20a8d1fe01520899ff69a73d69"