mirror of
https://github.com/radareorg/radare2-r2pipe.git
synced 2026-11-07 06:35:58 -10:00
Guard standalone C allocations against integer overflow
Use size_t counts and shared checked allocation helpers. Clean up on failure and preserve response framing when allocation fails. Shorten internal names and share the spawn command handling across platforms. Kudos to @anupamme for reporting the splitter overflow in PR #186: https://github.com/radareorg/radare2-r2pipe/pull/186
This commit is contained in:
1 parent
c9d198ccaa
commit
e6a2c8282b
1 file changed
+308
-306
+308
-306
@@ -8,12 +8,12 @@
|
||||
* #define R2P_ENABLE_SPAWN 1
|
||||
* #include "r2pipe.inc.c"
|
||||
*
|
||||
* int main(void) {
|
||||
* R2Pipe *r = r2p_open(R2P_SPAWN, "/bin/ls", "-aaa");
|
||||
* char *out = r2p_cmd(r, "pd 5");
|
||||
* puts(out);
|
||||
* free(out);
|
||||
* r2p_close(r);
|
||||
* int main (void) {
|
||||
* R2Pipe *r = r2p_open (R2P_SPAWN, "/bin/ls", "-aaa");
|
||||
* char *out = r2p_cmd (r, "pd 5");
|
||||
* puts (out);
|
||||
* free (out);
|
||||
* r2p_close (r);
|
||||
* }
|
||||
*
|
||||
* Use only libc and platform APIs. No json, no sockets, no deps.
|
||||
@@ -27,33 +27,34 @@
|
||||
#define R2P_ENABLE_DLOPEN 1
|
||||
#endif
|
||||
#ifndef R2P_ENABLE_SPAWN
|
||||
#define R2P_ENABLE_SPAWN 1
|
||||
#define R2P_ENABLE_SPAWN 1
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
# define R2P_WINDOWS 1
|
||||
# include <windows.h>
|
||||
#define R2P_WINDOWS 1
|
||||
#include <windows.h>
|
||||
#else
|
||||
# define R2P_UNIX 1
|
||||
# if R2P_ENABLE_SPAWN
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/wait.h>
|
||||
# endif
|
||||
# if R2P_ENABLE_DLOPEN
|
||||
# include <dlfcn.h>
|
||||
# endif
|
||||
#define R2P_UNIX 1
|
||||
#if R2P_ENABLE_SPAWN
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#if R2P_ENABLE_DLOPEN
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
R2P_DLOPEN = 0,
|
||||
R2P_SPAWN = 1
|
||||
R2P_SPAWN = 1
|
||||
} R2PipeMode;
|
||||
|
||||
typedef struct R2Pipe R2Pipe;
|
||||
@@ -61,48 +62,64 @@ typedef struct R2Pipe R2Pipe;
|
||||
struct R2Pipe {
|
||||
int mode;
|
||||
#if R2P_ENABLE_DLOPEN
|
||||
void *lib;
|
||||
void *core;
|
||||
void *(*fn_new)(void);
|
||||
void (*fn_free)(void *);
|
||||
char *(*fn_cmd_str)(void *, const char *);
|
||||
void *lib;
|
||||
void *core;
|
||||
void *(*fn_new) (void);
|
||||
void (*fn_free) (void *);
|
||||
char *(*fn_cmd_str) (void *, const char *);
|
||||
#endif
|
||||
#if R2P_ENABLE_SPAWN
|
||||
# if R2P_WINDOWS
|
||||
#if R2P_WINDOWS
|
||||
HANDLE child;
|
||||
HANDLE in_rd; /* read side: child's stdout */
|
||||
HANDLE out_wr; /* write side: child's stdin */
|
||||
# else
|
||||
HANDLE in_rd; /* read side: child's stdout */
|
||||
HANDLE out_wr; /* write side: child's stdin */
|
||||
#else
|
||||
int pid;
|
||||
int in_fd;
|
||||
int out_fd;
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ---- public api ---------------------------------------------------- */
|
||||
static R2Pipe *r2p_open(int mode, const char *file, const char *flags);
|
||||
static char *r2p_cmd (R2Pipe *r, const char *cmd);
|
||||
static void r2p_close(R2Pipe *r);
|
||||
static char *r2p_cmd(R2Pipe *r, const char *cmd);
|
||||
static void r2p_close(R2Pipe *r);
|
||||
|
||||
/* ---- helpers ------------------------------------------------------- */
|
||||
static char **r2p__split(const char *s, int *n_out) {
|
||||
*n_out = 0;
|
||||
if (!s || !*s) {
|
||||
static void *alloc_extra(size_t size, size_t extra) {
|
||||
return size > SIZE_MAX - extra? NULL: malloc (size + extra);
|
||||
}
|
||||
|
||||
static void *grow(void *buf, size_t *cap, size_t elem_size) {
|
||||
/* Check both doubling the element count and converting it to bytes. */
|
||||
if (*cap > SIZE_MAX / 2 / elem_size) {
|
||||
return NULL;
|
||||
}
|
||||
int cap = 8;
|
||||
int n = 0;
|
||||
char **argv = (char **)calloc((size_t)cap, sizeof(char *));
|
||||
size_t newcap = *cap * 2;
|
||||
void *nb = realloc (buf, newcap * elem_size);
|
||||
if (nb) {
|
||||
*cap = newcap;
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
#if R2P_ENABLE_DLOPEN || (R2P_ENABLE_SPAWN && !R2P_WINDOWS)
|
||||
static void free_split(char **argv, size_t n) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
free (argv[i]);
|
||||
}
|
||||
free (argv);
|
||||
}
|
||||
|
||||
static char **split(const char *s, size_t *n_out) {
|
||||
*n_out = 0;
|
||||
size_t cap = 8, n = 0;
|
||||
char **argv = (char **)calloc (cap, sizeof (char *));
|
||||
if (!argv) {
|
||||
return NULL;
|
||||
}
|
||||
char *copy = strdup(s);
|
||||
if (!copy) {
|
||||
free(argv);
|
||||
return NULL;
|
||||
}
|
||||
char *p = copy;
|
||||
const char *p = s? s: "";
|
||||
while (*p) {
|
||||
while (*p == ' ' || *p == '\t') {
|
||||
p++;
|
||||
@@ -110,159 +127,143 @@ static char **r2p__split(const char *s, int *n_out) {
|
||||
if (!*p) {
|
||||
break;
|
||||
}
|
||||
char *start = p;
|
||||
while (*p && *p != ' ' && *p != '\t') {
|
||||
p++;
|
||||
}
|
||||
size_t len = (size_t)(p - start);
|
||||
if (n + 2 > cap) {
|
||||
cap *= 2;
|
||||
char **nb = (char **)realloc(argv, (size_t)cap * sizeof(char *));
|
||||
const char *start = p;
|
||||
size_t len = strcspn (p, " \t");
|
||||
p += len;
|
||||
if (n == cap - 1) {
|
||||
char **nb = (char **)grow (argv, &cap, sizeof (char *));
|
||||
if (!nb) {
|
||||
break;
|
||||
goto fail;
|
||||
}
|
||||
argv = nb;
|
||||
}
|
||||
argv[n] = (char *)malloc(len + 1);
|
||||
argv[n] = (char *)alloc_extra (len, 1);
|
||||
if (!argv[n]) {
|
||||
break;
|
||||
goto fail;
|
||||
}
|
||||
memcpy(argv[n], start, len);
|
||||
memcpy (argv[n], start, len);
|
||||
argv[n][len] = '\0';
|
||||
n++;
|
||||
}
|
||||
free(copy);
|
||||
if (argv) {
|
||||
argv[n] = NULL;
|
||||
}
|
||||
argv[n] = NULL;
|
||||
*n_out = n;
|
||||
return argv;
|
||||
}
|
||||
|
||||
#if R2P_ENABLE_DLOPEN
|
||||
static void r2p__free_split(char **argv, int n) {
|
||||
if (!argv) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(argv[i]);
|
||||
}
|
||||
free(argv);
|
||||
fail:
|
||||
free_split (argv, n);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---- dlopen backend ----------------------------------------------- */
|
||||
#if R2P_ENABLE_DLOPEN
|
||||
|
||||
static void *r2p__lib_open(void) {
|
||||
static void *lib_open(void) {
|
||||
static const char *names[] = {
|
||||
# if R2P_WINDOWS
|
||||
#if R2P_WINDOWS
|
||||
"libr_core.dll",
|
||||
"r_core.dll",
|
||||
# elif defined(__APPLE__)
|
||||
"r_core.dll",
|
||||
#elif defined(__APPLE__)
|
||||
"libr_core.dylib",
|
||||
"/opt/homebrew/lib/libr_core.dylib",
|
||||
"/usr/local/lib/libr_core.dylib",
|
||||
# else
|
||||
"/opt/homebrew/lib/libr_core.dylib",
|
||||
"/usr/local/lib/libr_core.dylib",
|
||||
#else
|
||||
"libr_core.so",
|
||||
"libr_core.so.0",
|
||||
# endif
|
||||
"libr_core.so.0",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
for (int i = 0; names[i]; i++) {
|
||||
# if R2P_WINDOWS
|
||||
HMODULE h = LoadLibraryA(names[i]);
|
||||
#if R2P_WINDOWS
|
||||
HMODULE h = LoadLibraryA (names[i]);
|
||||
if (h) {
|
||||
return (void *)h;
|
||||
}
|
||||
# else
|
||||
void *h = dlopen(names[i], RTLD_NOW | RTLD_GLOBAL);
|
||||
#else
|
||||
void *h = dlopen (names[i], RTLD_NOW | RTLD_GLOBAL);
|
||||
if (h) {
|
||||
return h;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *r2p__sym(void *lib, const char *name) {
|
||||
# if R2P_WINDOWS
|
||||
return (void *)GetProcAddress((HMODULE)lib, name);
|
||||
# else
|
||||
return dlsym(lib, name);
|
||||
# endif
|
||||
static void *lib_sym(void *lib, const char *name) {
|
||||
#if R2P_WINDOWS
|
||||
return (void *)GetProcAddress ((HMODULE)lib, name);
|
||||
#else
|
||||
return dlsym (lib, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void r2p__lib_close(void *lib) {
|
||||
static void lib_close(void *lib) {
|
||||
if (!lib) {
|
||||
return;
|
||||
}
|
||||
# if R2P_WINDOWS
|
||||
FreeLibrary((HMODULE)lib);
|
||||
# else
|
||||
dlclose(lib);
|
||||
# endif
|
||||
#if R2P_WINDOWS
|
||||
FreeLibrary ((HMODULE)lib);
|
||||
#else
|
||||
dlclose (lib);
|
||||
#endif
|
||||
}
|
||||
|
||||
static R2Pipe *r2p__open_dlopen(const char *file, const char *flags) {
|
||||
R2Pipe *r = (R2Pipe *)calloc(1, sizeof(R2Pipe));
|
||||
static R2Pipe *open_dlopen(const char *file, const char *flags) {
|
||||
R2Pipe *r = (R2Pipe *)calloc (1, sizeof (R2Pipe));
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
r->mode = R2P_DLOPEN;
|
||||
r->lib = r2p__lib_open();
|
||||
r->lib = lib_open ();
|
||||
if (!r->lib) {
|
||||
fprintf(stderr, "r2pipe: cannot load libr_core\n");
|
||||
free(r);
|
||||
return NULL;
|
||||
fprintf (stderr, "r2pipe: cannot load libr_core\n");
|
||||
goto fail;
|
||||
}
|
||||
/* prefer r_core_new0 (fully-initializing ctor), fall back to r_core_new */
|
||||
void *sn = r2p__sym(r->lib, "r_core_new0");
|
||||
void *sn = lib_sym (r->lib, "r_core_new0");
|
||||
if (!sn) {
|
||||
sn = r2p__sym(r->lib, "r_core_new");
|
||||
sn = lib_sym (r->lib, "r_core_new");
|
||||
}
|
||||
void *sf = r2p__sym(r->lib, "r_core_free");
|
||||
void *sc = r2p__sym(r->lib, "r_core_cmd_str");
|
||||
void *sf = lib_sym (r->lib, "r_core_free");
|
||||
void *sc = lib_sym (r->lib, "r_core_cmd_str");
|
||||
if (!sn || !sf || !sc) {
|
||||
fprintf(stderr, "r2pipe: missing r_core_* symbols\n");
|
||||
r2p__lib_close(r->lib);
|
||||
free(r);
|
||||
return NULL;
|
||||
fprintf (stderr, "r2pipe: missing r_core_* symbols\n");
|
||||
goto fail;
|
||||
}
|
||||
r->fn_new = (void *(*)(void))sn;
|
||||
r->fn_free = (void (*)(void *))sf;
|
||||
r->fn_cmd_str = (char *(*)(void *, const char *))sc;
|
||||
r->core = r->fn_new();
|
||||
r->fn_new = (void *(*) (void))sn;
|
||||
r->fn_free = (void (*) (void *))sf;
|
||||
r->fn_cmd_str = (char *(*) (void *, const char *))sc;
|
||||
r->core = r->fn_new ();
|
||||
if (!r->core) {
|
||||
r2p__lib_close(r->lib);
|
||||
free(r);
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
/* apply each flag as an r2 command (in r2, "-d", "-aaa", ... map to
|
||||
* the same behavior as the commandline flags of the same name). */
|
||||
int nf = 0;
|
||||
char **fa = r2p__split(flags, &nf);
|
||||
for (int i = 0; i < nf; i++) {
|
||||
char *o = r->fn_cmd_str(r->core, fa[i]);
|
||||
if (o) {
|
||||
free(o);
|
||||
}
|
||||
size_t nf = 0;
|
||||
char **fa = split (flags, &nf);
|
||||
if (!fa) {
|
||||
goto fail;
|
||||
}
|
||||
r2p__free_split(fa, nf);
|
||||
for (size_t i = 0; i < nf; i++) {
|
||||
free (r->fn_cmd_str (r->core, fa[i]));
|
||||
}
|
||||
free_split (fa, nf);
|
||||
/* open the binary last */
|
||||
if (file && *file) {
|
||||
size_t len = strlen(file) + 4;
|
||||
char *oc = (char *)malloc(len);
|
||||
if (oc) {
|
||||
snprintf(oc, len, "o %s", file);
|
||||
char *o = r->fn_cmd_str(r->core, oc);
|
||||
if (o) {
|
||||
free(o);
|
||||
}
|
||||
free(oc);
|
||||
size_t len = strlen (file);
|
||||
char *oc = (char *)alloc_extra (len, 3);
|
||||
if (!oc) {
|
||||
goto fail;
|
||||
}
|
||||
snprintf (oc, len + 3, "o %s", file);
|
||||
free (r->fn_cmd_str (r->core, oc));
|
||||
free (oc);
|
||||
}
|
||||
return r;
|
||||
|
||||
fail:
|
||||
r2p_close (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* R2P_ENABLE_DLOPEN */
|
||||
@@ -270,190 +271,170 @@ static R2Pipe *r2p__open_dlopen(const char *file, const char *flags) {
|
||||
/* ---- spawn backend ------------------------------------------------- */
|
||||
#if R2P_ENABLE_SPAWN
|
||||
|
||||
# if R2P_WINDOWS
|
||||
#if R2P_WINDOWS
|
||||
|
||||
static R2Pipe *r2p__open_spawn(const char *file, const char *flags) {
|
||||
R2Pipe *r = (R2Pipe *)calloc(1, sizeof(R2Pipe));
|
||||
static R2Pipe *open_spawn(const char *file, const char *flags) {
|
||||
R2Pipe *r = (R2Pipe *)calloc (1, sizeof (R2Pipe));
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
r->mode = R2P_SPAWN;
|
||||
/* build cmdline: radare2 <flags> -q0 "<file>" */
|
||||
size_t need = strlen("radare2.exe -q0 ") + 8;
|
||||
if (flags) {
|
||||
need += strlen(flags) + 2;
|
||||
}
|
||||
if (file) {
|
||||
need += strlen(file) + 4;
|
||||
}
|
||||
char *cmdline = (char *)malloc(need);
|
||||
if (!cmdline) {
|
||||
free(r);
|
||||
size_t flen = flags? strlen (flags): 0;
|
||||
size_t len = file? strlen (file): 0;
|
||||
if (flen > SIZE_MAX - len) {
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
size_t need = flen + len;
|
||||
char *cmdline = (char *)alloc_extra (need, sizeof ("radare2.exe -q0 \"\""));
|
||||
if (!cmdline) {
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
need += sizeof ("radare2.exe -q0 \"\"");
|
||||
if (flags && *flags) {
|
||||
if (file && *file) {
|
||||
snprintf(cmdline, need, "radare2.exe %s -q0 \"%s\"", flags, file);
|
||||
snprintf (cmdline, need, "radare2.exe %s -q0 \"%s\"", flags, file);
|
||||
} else {
|
||||
snprintf(cmdline, need, "radare2.exe %s -q0", flags);
|
||||
snprintf (cmdline, need, "radare2.exe %s -q0", flags);
|
||||
}
|
||||
} else {
|
||||
if (file && *file) {
|
||||
snprintf(cmdline, need, "radare2.exe -q0 \"%s\"", file);
|
||||
snprintf (cmdline, need, "radare2.exe -q0 \"%s\"", file);
|
||||
} else {
|
||||
snprintf(cmdline, need, "radare2.exe -q0");
|
||||
snprintf (cmdline, need, "radare2.exe -q0");
|
||||
}
|
||||
}
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.nLength = sizeof (sa);
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
HANDLE cin_rd = NULL, cin_wr = NULL, cout_rd = NULL, cout_wr = NULL;
|
||||
if (!CreatePipe(&cout_rd, &cout_wr, &sa, 0)) {
|
||||
free(cmdline);
|
||||
free(r);
|
||||
if (!CreatePipe (&cout_rd, &cout_wr, &sa, 0)) {
|
||||
free (cmdline);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
if (!CreatePipe(&cin_rd, &cin_wr, &sa, 0)) {
|
||||
CloseHandle(cout_rd);
|
||||
CloseHandle(cout_wr);
|
||||
free(cmdline);
|
||||
free(r);
|
||||
if (!CreatePipe (&cin_rd, &cin_wr, &sa, 0)) {
|
||||
CloseHandle (cout_rd);
|
||||
CloseHandle (cout_wr);
|
||||
free (cmdline);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
SetHandleInformation(cout_rd, HANDLE_FLAG_INHERIT, 0);
|
||||
SetHandleInformation(cin_wr, HANDLE_FLAG_INHERIT, 0);
|
||||
SetHandleInformation (cout_rd, HANDLE_FLAG_INHERIT, 0);
|
||||
SetHandleInformation (cin_wr, HANDLE_FLAG_INHERIT, 0);
|
||||
STARTUPINFOA si;
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory (&si, sizeof (si));
|
||||
si.cb = sizeof (si);
|
||||
si.hStdInput = cin_rd;
|
||||
si.hStdOutput = cout_wr;
|
||||
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||
si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
PROCESS_INFORMATION pi;
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
BOOL ok = CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
|
||||
free(cmdline);
|
||||
CloseHandle(cin_rd);
|
||||
CloseHandle(cout_wr);
|
||||
ZeroMemory (&pi, sizeof (pi));
|
||||
BOOL ok = CreateProcessA (NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
|
||||
free (cmdline);
|
||||
CloseHandle (cin_rd);
|
||||
CloseHandle (cout_wr);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "r2pipe: CreateProcess failed (radare2 in PATH?)\n");
|
||||
CloseHandle(cout_rd);
|
||||
CloseHandle(cin_wr);
|
||||
free(r);
|
||||
fprintf (stderr, "r2pipe: CreateProcess failed (radare2 in PATH?)\n");
|
||||
CloseHandle (cout_rd);
|
||||
CloseHandle (cin_wr);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
CloseHandle(pi.hThread);
|
||||
r->child = pi.hProcess;
|
||||
r->in_rd = cout_rd;
|
||||
CloseHandle (pi.hThread);
|
||||
r->child = pi.hProcess;
|
||||
r->in_rd = cout_rd;
|
||||
r->out_wr = cin_wr;
|
||||
/* consume banner up to NUL (on windows r2 emits it twice in some builds) */
|
||||
char c;
|
||||
DWORD got;
|
||||
while (ReadFile(r->in_rd, &c, 1, &got, NULL) && got == 1 && c != '\0') {}
|
||||
while (ReadFile (r->in_rd, &c, 1, &got, NULL) && got == 1 && c != '\0') {
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *r2p__cmd_spawn(R2Pipe *r, const char *cmd) {
|
||||
size_t cl = strlen(cmd);
|
||||
char *line = (char *)malloc(cl + 2);
|
||||
if (!line) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(line, cmd, cl);
|
||||
line[cl] = '\n';
|
||||
line[cl + 1] = '\0';
|
||||
DWORD wrote;
|
||||
WriteFile(r->out_wr, line, (DWORD)(cl + 1), &wrote, NULL);
|
||||
free(line);
|
||||
size_t cap = 4096, len = 0;
|
||||
char *buf = (char *)malloc(cap);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
char c;
|
||||
DWORD got;
|
||||
while (ReadFile(r->in_rd, &c, 1, &got, NULL) && got == 1) {
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
if (len + 2 > cap) {
|
||||
cap *= 2;
|
||||
char *nb = (char *)realloc(buf, cap);
|
||||
if (!nb) {
|
||||
break;
|
||||
}
|
||||
buf = nb;
|
||||
}
|
||||
buf[len++] = c;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void r2p__close_spawn(R2Pipe *r) {
|
||||
static void close_spawn(R2Pipe *r) {
|
||||
const char *bye = "q!!\n";
|
||||
DWORD w;
|
||||
WriteFile(r->out_wr, bye, (DWORD)strlen(bye), &w, NULL);
|
||||
CloseHandle(r->out_wr);
|
||||
CloseHandle(r->in_rd);
|
||||
WaitForSingleObject(r->child, 5000);
|
||||
CloseHandle(r->child);
|
||||
WriteFile (r->out_wr, bye, (DWORD)strlen (bye), &w, NULL);
|
||||
CloseHandle (r->out_wr);
|
||||
CloseHandle (r->in_rd);
|
||||
WaitForSingleObject (r->child, 5000);
|
||||
CloseHandle (r->child);
|
||||
}
|
||||
|
||||
# else /* unix spawn */
|
||||
#else /* unix spawn */
|
||||
|
||||
static R2Pipe *r2p__open_spawn(const char *file, const char *flags) {
|
||||
int in_pipe[2]; /* child stdout -> parent */
|
||||
static R2Pipe *open_spawn(const char *file, const char *flags) {
|
||||
int in_pipe[2]; /* child stdout -> parent */
|
||||
int out_pipe[2]; /* parent -> child stdin */
|
||||
if (pipe(in_pipe) != 0) {
|
||||
if (pipe (in_pipe) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (pipe(out_pipe) != 0) {
|
||||
close(in_pipe[0]);
|
||||
close(in_pipe[1]);
|
||||
if (pipe (out_pipe) != 0) {
|
||||
close (in_pipe[0]);
|
||||
close (in_pipe[1]);
|
||||
return NULL;
|
||||
}
|
||||
pid_t pid = fork();
|
||||
R2Pipe *r = (R2Pipe *)calloc (1, sizeof (R2Pipe));
|
||||
if (!r) {
|
||||
close (in_pipe[0]);
|
||||
close (in_pipe[1]);
|
||||
close (out_pipe[0]);
|
||||
close (out_pipe[1]);
|
||||
return NULL;
|
||||
}
|
||||
pid_t pid = fork ();
|
||||
if (pid < 0) {
|
||||
close(in_pipe[0]);
|
||||
close(in_pipe[1]);
|
||||
close(out_pipe[0]);
|
||||
close(out_pipe[1]);
|
||||
close (in_pipe[0]);
|
||||
close (in_pipe[1]);
|
||||
close (out_pipe[0]);
|
||||
close (out_pipe[1]);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
dup2(out_pipe[0], 0);
|
||||
dup2(in_pipe[1], 1);
|
||||
close(in_pipe[0]);
|
||||
close(in_pipe[1]);
|
||||
close(out_pipe[0]);
|
||||
close(out_pipe[1]);
|
||||
int nf = 0;
|
||||
char **fa = r2p__split(flags, &nf);
|
||||
dup2 (out_pipe[0], 0);
|
||||
dup2 (in_pipe[1], 1);
|
||||
close (in_pipe[0]);
|
||||
close (in_pipe[1]);
|
||||
close (out_pipe[0]);
|
||||
close (out_pipe[1]);
|
||||
size_t nf = 0;
|
||||
char **fa = split (flags, &nf);
|
||||
if (!fa) {
|
||||
_exit (127);
|
||||
}
|
||||
/* r2 cli is order-sensitive: when "-0" appears BEFORE the quit
|
||||
* flag, NUL framing comes out broken (zero bytes on stdout). To
|
||||
* stay safe regardless of what the caller passed, we always put
|
||||
* "-q0" first — and skip it if the caller already gave -0 / -q0
|
||||
* to avoid double quit. */
|
||||
int has_zero = 0;
|
||||
for (int i = 0; i < nf; i++) {
|
||||
if (!strcmp(fa[i], "-0") || !strcmp(fa[i], "-q0")) {
|
||||
for (size_t i = 0; i < nf; i++) {
|
||||
if (!strcmp (fa[i], "-0") || !strcmp (fa[i], "-q0")) {
|
||||
has_zero = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int ac = 0;
|
||||
char **av = (char **)calloc((size_t)(nf + 4), sizeof(char *));
|
||||
if (nf > SIZE_MAX / sizeof (char *) - 4) {
|
||||
_exit (127);
|
||||
}
|
||||
size_t ac = 0;
|
||||
char **av = (char **)calloc (nf + 4, sizeof (char *));
|
||||
if (!av) {
|
||||
_exit(127);
|
||||
_exit (127);
|
||||
}
|
||||
av[ac++] = (char *)"radare2";
|
||||
av[ac++] = (char *)"-q0";
|
||||
for (int i = 0; i < nf; i++) {
|
||||
for (size_t i = 0; i < nf; i++) {
|
||||
/* drop a redundant -q0 from the caller; -0 is fine after -q0 */
|
||||
if (has_zero && !strcmp(fa[i], "-q0")) {
|
||||
if (has_zero && !strcmp (fa[i], "-q0")) {
|
||||
continue;
|
||||
}
|
||||
av[ac++] = fa[i];
|
||||
@@ -462,18 +443,12 @@ static R2Pipe *r2p__open_spawn(const char *file, const char *flags) {
|
||||
av[ac++] = (char *)file;
|
||||
}
|
||||
av[ac] = NULL;
|
||||
execvp("radare2", av);
|
||||
_exit(127);
|
||||
execvp ("radare2", av);
|
||||
_exit (127);
|
||||
}
|
||||
/* parent */
|
||||
close(in_pipe[1]);
|
||||
close(out_pipe[0]);
|
||||
R2Pipe *r = (R2Pipe *)calloc(1, sizeof(R2Pipe));
|
||||
if (!r) {
|
||||
close(in_pipe[0]);
|
||||
close(out_pipe[1]);
|
||||
return NULL;
|
||||
}
|
||||
close (in_pipe[1]);
|
||||
close (out_pipe[0]);
|
||||
r->mode = R2P_SPAWN;
|
||||
r->pid = (int)pid;
|
||||
r->in_fd = in_pipe[0];
|
||||
@@ -483,90 +458,117 @@ static R2Pipe *r2p__open_spawn(const char *file, const char *flags) {
|
||||
* in PATH), the read returns 0 and we treat this as open failure. */
|
||||
char c;
|
||||
int got_banner = 0;
|
||||
while (read(r->in_fd, &c, 1) == 1) {
|
||||
if (c == '\0') { got_banner = 1; break; }
|
||||
while (read (r->in_fd, &c, 1) == 1) {
|
||||
if (c == '\0') {
|
||||
got_banner = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!got_banner) {
|
||||
close(r->in_fd);
|
||||
close(r->out_fd);
|
||||
waitpid((pid_t)r->pid, NULL, 0);
|
||||
free(r);
|
||||
close (r->in_fd);
|
||||
close (r->out_fd);
|
||||
waitpid ((pid_t)r->pid, NULL, 0);
|
||||
free (r);
|
||||
return NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *r2p__cmd_spawn(R2Pipe *r, const char *cmd) {
|
||||
size_t cl = strlen(cmd);
|
||||
char *line = (char *)malloc(cl + 2);
|
||||
static void close_spawn(R2Pipe *r) {
|
||||
const char *bye = "q!!\n";
|
||||
ssize_t _w = write (r->out_fd, bye, strlen (bye));
|
||||
(void)_w;
|
||||
close (r->out_fd);
|
||||
close (r->in_fd);
|
||||
int st;
|
||||
waitpid ((pid_t)r->pid, &st, 0);
|
||||
}
|
||||
|
||||
#endif /* R2P_WINDOWS */
|
||||
|
||||
static char *cmd_spawn(R2Pipe *r, const char *cmd) {
|
||||
size_t cl = strlen (cmd);
|
||||
char *line = (char *)alloc_extra (cl, 1);
|
||||
if (!line) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(line, cmd, cl);
|
||||
memcpy (line, cmd, cl);
|
||||
line[cl] = '\n';
|
||||
line[cl + 1] = '\0';
|
||||
size_t total = cl + 1;
|
||||
size_t done = 0;
|
||||
while (done < total) {
|
||||
ssize_t k = write(r->out_fd, line + done, total - done);
|
||||
#if R2P_WINDOWS
|
||||
DWORD chunk = total - done > MAXDWORD? MAXDWORD: (DWORD) (total - done);
|
||||
DWORD wrote;
|
||||
if (!WriteFile (r->out_wr, line + done, chunk, &wrote, NULL) || !wrote) {
|
||||
free (line);
|
||||
return NULL;
|
||||
}
|
||||
done += wrote;
|
||||
#else
|
||||
ssize_t k = write (r->out_fd, line + done, total - done);
|
||||
if (k <= 0) {
|
||||
break;
|
||||
free (line);
|
||||
return NULL;
|
||||
}
|
||||
done += (size_t)k;
|
||||
#endif
|
||||
}
|
||||
free(line);
|
||||
free (line);
|
||||
size_t cap = 4096, len = 0;
|
||||
char *buf = (char *)malloc(cap);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
char c;
|
||||
while (read(r->in_fd, &c, 1) == 1) {
|
||||
char *buf = (char *)malloc (cap);
|
||||
for (;;) {
|
||||
char c;
|
||||
#if R2P_WINDOWS
|
||||
DWORD got;
|
||||
int ok = ReadFile (r->in_rd, &c, 1, &got, NULL) && got == 1;
|
||||
#else
|
||||
int ok = read (r->in_fd, &c, 1) == 1;
|
||||
#endif
|
||||
if (!ok) {
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
if (len + 2 > cap) {
|
||||
cap *= 2;
|
||||
char *nb = (char *)realloc(buf, cap);
|
||||
/* Drain a failed response to keep the next command's framing intact. */
|
||||
if (!buf) {
|
||||
continue;
|
||||
}
|
||||
if (len == cap - 1) {
|
||||
char *nb = (char *)grow (buf, &cap, 1);
|
||||
if (!nb) {
|
||||
break;
|
||||
free (buf);
|
||||
buf = NULL;
|
||||
continue;
|
||||
}
|
||||
buf = nb;
|
||||
}
|
||||
buf[len++] = c;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
if (buf) {
|
||||
buf[len] = '\0';
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void r2p__close_spawn(R2Pipe *r) {
|
||||
const char *bye = "q!!\n";
|
||||
ssize_t _w = write(r->out_fd, bye, strlen(bye));
|
||||
(void)_w;
|
||||
close(r->out_fd);
|
||||
close(r->in_fd);
|
||||
int st;
|
||||
waitpid((pid_t)r->pid, &st, 0);
|
||||
}
|
||||
|
||||
# endif /* R2P_WINDOWS */
|
||||
#endif /* R2P_ENABLE_SPAWN */
|
||||
|
||||
/* ---- dispatch ----------------------------------------------------- */
|
||||
static R2Pipe *r2p_open(int mode, const char *file, const char *flags) {
|
||||
#if R2P_ENABLE_DLOPEN
|
||||
if (mode == R2P_DLOPEN) {
|
||||
return r2p__open_dlopen(file, flags);
|
||||
return open_dlopen (file, flags);
|
||||
}
|
||||
#endif
|
||||
#if R2P_ENABLE_SPAWN
|
||||
if (mode == R2P_SPAWN) {
|
||||
return r2p__open_spawn(file, flags);
|
||||
return open_spawn (file, flags);
|
||||
}
|
||||
#endif
|
||||
(void)file;
|
||||
(void)flags;
|
||||
fprintf(stderr, "r2pipe: mode %d not available (check R2P_ENABLE_*)\n", mode);
|
||||
fprintf (stderr, "r2pipe: mode %d not available (check R2P_ENABLE_*)\n", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -576,12 +578,12 @@ static char *r2p_cmd(R2Pipe *r, const char *cmd) {
|
||||
}
|
||||
#if R2P_ENABLE_DLOPEN
|
||||
if (r->mode == R2P_DLOPEN) {
|
||||
return r->fn_cmd_str(r->core, cmd);
|
||||
return r->fn_cmd_str (r->core, cmd);
|
||||
}
|
||||
#endif
|
||||
#if R2P_ENABLE_SPAWN
|
||||
if (r->mode == R2P_SPAWN) {
|
||||
return r2p__cmd_spawn(r, cmd);
|
||||
return cmd_spawn (r, cmd);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
@@ -594,21 +596,21 @@ static void r2p_close(R2Pipe *r) {
|
||||
#if R2P_ENABLE_DLOPEN
|
||||
if (r->mode == R2P_DLOPEN) {
|
||||
if (r->core && r->fn_free) {
|
||||
r->fn_free(r->core);
|
||||
r->fn_free (r->core);
|
||||
}
|
||||
r2p__lib_close(r->lib);
|
||||
free(r);
|
||||
lib_close (r->lib);
|
||||
free (r);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if R2P_ENABLE_SPAWN
|
||||
if (r->mode == R2P_SPAWN) {
|
||||
r2p__close_spawn(r);
|
||||
free(r);
|
||||
close_spawn (r);
|
||||
free (r);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
free(r);
|
||||
free (r);
|
||||
}
|
||||
|
||||
#endif /* R2PIPE_INC_C */
|
||||
Reference in new issue
Block a user