Package: smemstat / 0.01.10-2

0001-Fix-null-ptr-dereference-when-UID-can-t-be-read-LP-1.patch Patch series | download
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
From 851c9d288a76b881ec547a61c2c3a8cc2b42f207 Mon Sep 17 00:00:00 2001
From: Colin Ian King <colin.king@canonical.com>
Date: Fri, 10 Jul 2015 00:33:25 +0100
Subject: [PATCH] Fix null ptr dereference when UID can't be read (LP:
 #1473245)
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

While stress testing a machine with a lot of low memory
pressure and processes fork/exiting very rapidly I found
that smemstat reads empty /proc/$pid/status files and hence
cannot get a process UID. This leads to no umame being
found for a new mem_info item and later on the deference
of m->uname->name segfaults on a null pointer deference
because m->uname is NULL.

Add a one-liner helper to check for the null uname and
return "<unknown>" for unknown UID uname lookups instead
of segfaulting.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 smemstat.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

Index: smemstat-0.01.10/smemstat.c
===================================================================
--- smemstat-0.01.10.orig/smemstat.c
+++ smemstat-0.01.10/smemstat.c
@@ -116,6 +116,16 @@ static void out_of_memory(const char *ms
 }
 
 /*
+ *  uname_name()
+ *	fetch name from uname, handle
+ *	unknown NULL unames too
+ */
+static inline const char *uname_name(uname_cache_t *uname)
+{
+	return uname ? uname->name : "<unknown>";
+}
+
+/*
  *  count_bits()
  *	count bits set, from C Programming Language 2nd Ed
  */
@@ -718,6 +728,13 @@ static int mem_get_by_proc(const pid_t p
 	if ((fp = fopen(path, "r")) == NULL)
 		return 0;
 
+	/*
+	 *  Find Uid and uname. Note that it may
+	 *  not be found, in which case new->uname is
+	 *  still NULL, so we need to always use
+	 *  uname_name() to fetch the uname to handle
+	 *  the NULL uname cases.
+	 */
 	while (fgets(buffer, sizeof(buffer), fp) != NULL) {
 		if (!strncmp(buffer, "Uid:", 4)) {
 			if (sscanf(buffer + 5, "%9i", &new_m->uid) == 1) {
@@ -848,12 +865,14 @@ static int mem_dump(FILE *json, mem_info
 
 		if (!(opt_flags & OPT_QUIET))
 			printf(" %5d %9s %9s %9s %9s %-10.10s %s\n",
-				m->pid, s_swap, s_uss, s_pss, s_rss, m->uname->name, cmd);
+				m->pid, s_swap, s_uss, s_pss, s_rss,
+				uname_name(m->uname), cmd);
 
 		if (json) {
 			fprintf(json, "      {\n");
 			fprintf(json, "        \"pid\":%d,\n", m->pid);
-			fprintf(json, "        \"user\":\"%s\",\n", m->uname->name);
+			fprintf(json, "        \"user\":\"%s\",\n",
+				uname_name(m->uname));
 			fprintf(json, "        \"command\":\"%s\",\n", cmd);
 			fprintf(json, "        \"swap\":%" PRIi64 ",\n", m->swap);
 			fprintf(json, "        \"uss\":%" PRIi64 ",\n", m->uss);
@@ -984,13 +1003,15 @@ static int mem_dump_diff(
 
 		if (!(opt_flags & OPT_QUIET))
 			printf(" %5d %9s %9s %9s %9s %-10.10s %s\n",
-				m->pid, s_swap, s_uss, s_pss, s_rss, m->uname->name, cmd);
+				m->pid, s_swap, s_uss, s_pss, s_rss,
+				uname_name(m->uname), cmd);
 
 		if (json) {
 			fprintf(json, "          {\n");
 			fprintf(json, "            \"pid\":%d,\n", m->pid);
 			fprintf(json, "            \"command\":\"%s\",\n", cmd);
-			fprintf(json, "            \"user\":\"%s\",\n", m->uname->name);
+			fprintf(json, "            \"user\":\"%s\",\n",
+				uname_name(m->uname));
 			fprintf(json, "            \"swap\":%" PRIi64 ",\n", m->swap);
 			fprintf(json, "            \"uss\":%" PRIi64 ",\n", m->uss);
 			fprintf(json, "            \"pss\":%" PRIi64 ",\n", m->pss);