summaryrefslogtreecommitdiff
blob: 3e0426634f4271fb9f5e685d766d3ad26691c721 (plain)
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
From 10fa5f6ba64b354b99b0f7b372e66e45bb4d9379 Mon Sep 17 00:00:00 2001
Message-ID: <10fa5f6ba64b354b99b0f7b372e66e45bb4d9379.1713033988.git.mprivozn@redhat.com>
In-Reply-To: <2127032ed8cd49001465dc0dce9f842e13467bc2.1713033988.git.mprivozn@redhat.com>
References: <2127032ed8cd49001465dc0dce9f842e13467bc2.1713033988.git.mprivozn@redhat.com>
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 15 Mar 2024 10:47:50 +0000
Subject: [PATCH 2/2] remote: check for negative array lengths before
 allocation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

While the C API entry points will validate non-negative lengths
for various parameters, the RPC server de-serialization code
will need to allocate memory for arrays before entering the C
API. These allocations will thus happen before the non-negative
length check is performed.

Passing a negative length to the g_new0 function will usually
result in a crash due to the negative length being treated as
a huge positive number.

This was found and diagnosed by ALT Linux Team with AFLplusplus.

CVE-2024-2494
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Found-by: Alexandr Shashkin <dutyrok@altlinux.org>
Co-developed-by: Alexander Kuznetsov <kuznetsovam@altlinux.org>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 8a3f8d957507c1f8223fdcf25a3ff885b15557f2)
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
---
 src/remote/remote_daemon_dispatch.c | 65 +++++++++++++++++++++++++++++
 src/rpc/gendispatch.pl              |  5 +++
 2 files changed, 70 insertions(+)

diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index 7daf503b51..7542caa952 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -2291,6 +2291,10 @@ remoteDispatchDomainGetSchedulerParameters(virNetServer *server G_GNUC_UNUSED,
     if (!conn)
         goto cleanup;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -2339,6 +2343,10 @@ remoteDispatchDomainGetSchedulerParametersFlags(virNetServer *server G_GNUC_UNUS
     if (!conn)
         goto cleanup;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -2497,6 +2505,10 @@ remoteDispatchDomainBlockStatsFlags(virNetServer *server G_GNUC_UNUSED,
         goto cleanup;
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -2717,6 +2729,14 @@ remoteDispatchDomainGetVcpuPinInfo(virNetServer *server G_GNUC_UNUSED,
     if (!(dom = get_nonnull_domain(conn, args->dom)))
         goto cleanup;
 
+    if (args->ncpumaps < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps must be non-negative"));
+        goto cleanup;
+    }
+    if (args->maplen < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maplen must be non-negative"));
+        goto cleanup;
+    }
     if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps > REMOTE_VCPUINFO_MAX"));
         goto cleanup;
@@ -2811,6 +2831,11 @@ remoteDispatchDomainGetEmulatorPinInfo(virNetServer *server G_GNUC_UNUSED,
     if (!(dom = get_nonnull_domain(conn, args->dom)))
         goto cleanup;
 
+    if (args->maplen < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maplen must be non-negative"));
+        goto cleanup;
+    }
+
     /* Allocate buffers to take the results */
     if (args->maplen > 0)
         cpumaps = g_new0(unsigned char, args->maplen);
@@ -2858,6 +2883,14 @@ remoteDispatchDomainGetVcpus(virNetServer *server G_GNUC_UNUSED,
     if (!(dom = get_nonnull_domain(conn, args->dom)))
         goto cleanup;
 
+    if (args->maxinfo < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo must be non-negative"));
+        goto cleanup;
+    }
+    if (args->maplen < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo must be non-negative"));
+        goto cleanup;
+    }
     if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo > REMOTE_VCPUINFO_MAX"));
         goto cleanup;
@@ -3096,6 +3129,10 @@ remoteDispatchDomainGetMemoryParameters(virNetServer *server G_GNUC_UNUSED,
 
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -3156,6 +3193,10 @@ remoteDispatchDomainGetNumaParameters(virNetServer *server G_GNUC_UNUSED,
 
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_NUMA_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -3216,6 +3257,10 @@ remoteDispatchDomainGetBlkioParameters(virNetServer *server G_GNUC_UNUSED,
 
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -3277,6 +3322,10 @@ remoteDispatchNodeGetCPUStats(virNetServer *server G_GNUC_UNUSED,
 
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -3339,6 +3388,10 @@ remoteDispatchNodeGetMemoryStats(virNetServer *server G_GNUC_UNUSED,
 
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_NODE_MEMORY_STATS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -3514,6 +3567,10 @@ remoteDispatchDomainGetBlockIoTune(virNetServer *server G_GNUC_UNUSED,
     if (!conn)
         goto cleanup;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -5079,6 +5136,10 @@ remoteDispatchDomainGetInterfaceParameters(virNetServer *server G_GNUC_UNUSED,
 
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
@@ -5299,6 +5360,10 @@ remoteDispatchNodeGetMemoryParameters(virNetServer *server G_GNUC_UNUSED,
 
     flags = args->flags;
 
+    if (args->nparams < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+        goto cleanup;
+    }
     if (args->nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
         goto cleanup;
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index fa45d15a92..294e21f8a1 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -1070,6 +1070,11 @@ elsif ($mode eq "server") {
         print "\n";
 
         if ($single_ret_as_list) {
+            print "    if (args->$single_ret_list_max_var < 0) {\n";
+            print "        virReportError(VIR_ERR_RPC,\n";
+            print "                       \"%s\", _(\"max$single_ret_list_name must be non-negative\"));\n";
+            print "        goto cleanup;\n";
+            print "    }\n";
             print "    if (args->$single_ret_list_max_var > $single_ret_list_max_define) {\n";
             print "        virReportError(VIR_ERR_RPC,\n";
             print "                       \"%s\", _(\"max$single_ret_list_name > $single_ret_list_max_define\"));\n";
-- 
2.43.2