Files
proxmark3/client/src/pm3.c
T
Jonathan YenandClaude Opus 5 d515458973 fix: heap overflow in pm3_grabbed_output_get
pm3_grabbed_output_get null-terminated the captured output at
g_grabbed_output.size, but size is the allocated capacity, not the number of
bytes written -- ui.c grows it by MAX_PRINT_BUFFER at a time and tracks the
used length separately in idx. Every call therefore wrote one zero byte past
the end of the heap allocation.

The CLI mostly survives it because it calls the function once or twice and
then exits, so the corrupted malloc metadata is never reused. A long-running
libpm3 client that captures output on every command does not: the damage
surfaces later, far from the cause. It was found as a SIGTRAP inside an
unrelated AppKit autorelease pool.

Reproduced against real hardware:

  MALLOC_STRICT_SIZE=1 MallocGuardEdges=1 \
    DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib ./pm3run <port> "hw version"

which crashes with SIGSEGV inside pm3_grabbed_output_get before this change
and exits cleanly with identical captured output after it.

Terminating at idx is always in bounds: the grabber guarantees at least
MAX_PRINT_BUFFER bytes of headroom before each write, so idx is strictly less
than size.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjGgtnsvWJHAMYEksAiYuf
2026-08-20 21:44:36 -04:00

95 lines
2.9 KiB
C

//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// User API
//-----------------------------------------------------------------------------
#include "pm3.h"
#include <stdlib.h>
#include "proxmark3.h"
#include "cmdmain.h"
#include "ui.h"
#include "usart_defs.h"
#include "util_posix.h"
#include "comms.h"
#include "preferences.h"
pm3_device_t *pm3_open(const char *port) {
pm3_init();
preferences_load();
OpenProxmark(&g_session.current_device, port, false, 20, false, USART_BAUD_RATE);
if (g_session.pm3_present && (TestProxmark(g_session.current_device) != PM3_SUCCESS)) {
PrintAndLogEx(ERR, _RED_("ERROR:") " cannot communicate with the Proxmark3\n");
CloseProxmark(g_session.current_device);
}
if ((port != NULL) && (!g_session.pm3_present))
exit(EXIT_FAILURE);
if (!g_session.pm3_present) {
PrintAndLogEx(INFO, _RED_("OFFLINE") " mode");
}
// For now, there is no real device context:
return g_session.current_device;
}
void pm3_close(pm3_device_t *dev) {
// Clean up the port
if (g_session.pm3_present) {
clearCommandBuffer();
SendCommandNG(CMD_QUIT_SESSION, NULL, 0);
msleep(100); // Make sure command is sent before killing client
CloseProxmark(dev);
}
free_grabber();
}
int pm3_console(pm3_device_t *dev, const char *cmd, bool capture, bool quiet) {
// For now, there is no real device context:
(void) dev;
uint8_t prev_printAndLog = g_printAndLog;
if (capture) {
g_printAndLog |= PRINTANDLOG_GRAB;
}
if (quiet) {
g_printAndLog &= ~PRINTANDLOG_PRINT;
}
int ret = CommandReceived(cmd);
g_printAndLog = prev_printAndLog;
return ret;
}
const char *pm3_name_get(pm3_device_t *dev) {
return dev->g_conn->serial_port_name;
}
const char *pm3_grabbed_output_get(pm3_device_t *dev) {
if (g_grabbed_output.ptr != NULL) {
char *tmp = g_grabbed_output.ptr;
tmp[g_grabbed_output.idx] = 0;
g_grabbed_output.idx = 0;
g_grabbed_output.size = 0;
return tmp;
} else {
return "";
}
}
pm3_device_t *pm3_get_current_dev(void) {
return g_session.current_device;
}