Skip to content

Commit f7016cb

Browse files
fix: defensive hardening in EMI provider - pre-alloc buffer, bounds checks, guard against zero metadata size
1 parent c4491d4 commit f7016cb

2 files changed

Lines changed: 44 additions & 17 deletions

File tree

metric_providers/cpu/energy/rapl/emi/component/provider.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ def start_profiling(self):
3939
call_string = os.path.join(self._current_dir, self._metric_provider_executable)
4040
cmd = [call_string, '-i', str(self._sampling_rate)]
4141

42-
print(' '.join(cmd))
43-
4442
self._stdout_file = open(self._filename, 'w', encoding='utf-8') # pylint: disable=consider-using-with
4543
self._ps = subprocess.Popen(
4644
cmd,

metric_providers/cpu/energy/rapl/emi/component/source.c

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ typedef struct {
7777
typedef struct {
7878
HANDLE handle;
7979
USHORT version;
80-
USHORT channel_count; /* named channels only */
81-
ULONG measure_buf_size; /* buffer for ALL channels (incl. unnamed) */
80+
USHORT channel_count; /* named channels only */
81+
ULONG measure_buf_size; /* buffer size for ALL channels (incl. unnamed) */
82+
BYTE *measure_buf; /* pre-allocated measurement buffer */
8283
emi_channel_t channels[MAX_CHANNELS];
8384
} emi_device_t;
8485

@@ -140,6 +141,7 @@ static unsigned int parse_uint(const char *s)
140141
*/
141142
static int normalize_name(const WCHAR *wname, char *out, size_t out_size)
142143
{
144+
if (out_size == 0) return 0;
143145
size_t i = 0;
144146
for (const WCHAR *p = wname; *p && i < out_size - 1; p++) {
145147
char c;
@@ -237,6 +239,12 @@ static int open_emi_devices(emi_device_t *devs, int max_devs)
237239
continue;
238240
}
239241

242+
if (msize.MetadataSize == 0) {
243+
fprintf(stderr, "Warning: EMI device %lu reported zero metadata size — skipping\n", idx);
244+
CloseHandle(h);
245+
continue;
246+
}
247+
240248
BYTE *meta = malloc(msize.MetadataSize);
241249
if (!meta) { CloseHandle(h); continue; }
242250

@@ -260,25 +268,40 @@ static int open_emi_devices(emi_device_t *devs, int max_devs)
260268
dev->measure_buf_size = sizeof(EMI_CHANNEL_MEASUREMENT_DATA);
261269

262270
} else { /* V2 */
263-
const EMI_METADATA_V2 *m = (const EMI_METADATA_V2 *)meta;
264-
const EMI_CHANNEL_V2 *ch = m->Channels;
271+
const EMI_METADATA_V2 *m = (const EMI_METADATA_V2 *)meta;
272+
const EMI_CHANNEL_V2 *ch = m->Channels;
273+
const BYTE *meta_end = meta + msize.MetadataSize;
265274
USHORT valid = 0;
266275

267276
for (USHORT c = 0; c < m->ChannelCount; c++) {
277+
/* Bound check: current entry must fit inside the metadata buffer */
278+
if ((const BYTE *)ch + sizeof(EMI_CHANNEL_V2) > meta_end) {
279+
fprintf(stderr, "Warning: EMI metadata truncated on device %lu at channel %u — stopping\n", idx, c);
280+
break;
281+
}
282+
268283
if (valid < MAX_CHANNELS &&
269284
normalize_name(ch->ChannelName,
270285
dev->channels[valid].name, MAX_NAME_LEN)) {
271286
dev->channels[valid].buf_index = c;
272287
valid++;
273288
}
289+
274290
/*
275291
* Advance to the next EMI_CHANNEL_V2 entry.
276292
* ChannelNameSize includes the null terminator, in bytes.
277293
* The SDK requires 8-byte alignment between entries.
278294
*/
279295
size_t stride = offsetof(EMI_CHANNEL_V2, ChannelName) + ch->ChannelNameSize;
280296
stride = (stride + 7) & ~(size_t)7;
281-
ch = (const EMI_CHANNEL_V2 *)((const BYTE *)ch + stride);
297+
298+
/* Bound check: next entry must not start past the metadata buffer */
299+
const BYTE *next = (const BYTE *)ch + stride;
300+
if (c + 1 < m->ChannelCount && next >= meta_end) {
301+
fprintf(stderr, "Warning: EMI metadata layout invalid on device %lu — truncating at channel %u\n", idx, c);
302+
break;
303+
}
304+
ch = (const EMI_CHANNEL_V2 *)next;
282305
}
283306
dev->channel_count = valid;
284307
/*
@@ -297,6 +320,14 @@ static int open_emi_devices(emi_device_t *devs, int max_devs)
297320
continue;
298321
}
299322

323+
/* Pre-allocate the measurement buffer once; reused every sample tick */
324+
dev->measure_buf = malloc(dev->measure_buf_size);
325+
if (!dev->measure_buf) {
326+
fprintf(stderr, "Warning: out of memory for EMI device %lu measurement buffer — skipping\n", idx);
327+
CloseHandle(h);
328+
continue;
329+
}
330+
300331
count++;
301332
}
302333

@@ -338,20 +369,16 @@ static void sample_devices(emi_device_t *devs, int count, const clock_state_t *c
338369
for (int i = 0; i < count; i++) {
339370
emi_device_t *dev = &devs[i];
340371

341-
BYTE *buf = malloc(dev->measure_buf_size);
342-
if (!buf) continue;
343-
344372
DWORD ret = 0;
345373
if (!DeviceIoControl(dev->handle, IOCTL_EMI_GET_MEASUREMENT,
346-
NULL, 0, buf, dev->measure_buf_size, &ret, NULL)) {
374+
NULL, 0, dev->measure_buf, dev->measure_buf_size, &ret, NULL)) {
347375
fprintf(stderr, "Warning: IOCTL_EMI_GET_MEASUREMENT failed for device %d (%lu)\n",
348376
i, GetLastError());
349-
free(buf);
350377
continue;
351378
}
352379

353380
const EMI_CHANNEL_MEASUREMENT_DATA *data =
354-
(const EMI_CHANNEL_MEASUREMENT_DATA *)buf;
381+
(const EMI_CHANNEL_MEASUREMENT_DATA *)dev->measure_buf;
355382

356383
for (USHORT c = 0; c < dev->channel_count; c++) {
357384
emi_channel_t *ch = &dev->channels[c];
@@ -379,8 +406,6 @@ static void sample_devices(emi_device_t *devs, int count, const clock_state_t *c
379406
ch->prev_energy = energy;
380407
ch->has_prev = 1;
381408
}
382-
383-
free(buf);
384409
}
385410
}
386411

@@ -410,8 +435,10 @@ int main(int argc, char *argv[])
410435
}
411436

412437
if (check_mode) {
413-
for (int i = 0; i < device_count; i++)
438+
for (int i = 0; i < device_count; i++) {
439+
free(devs[i].measure_buf);
414440
CloseHandle(devs[i].handle);
441+
}
415442
return 0;
416443
}
417444

@@ -434,7 +461,9 @@ int main(int argc, char *argv[])
434461

435462
/* Not reached in normal operation; shown for completeness */
436463
timeEndPeriod(1);
437-
for (int i = 0; i < device_count; i++)
464+
for (int i = 0; i < device_count; i++) {
465+
free(devs[i].measure_buf);
438466
CloseHandle(devs[i].handle);
467+
}
439468
return 0;
440469
}

0 commit comments

Comments
 (0)