I want to set a watchpoint (break on hardware write) temporarily in my C++ program to find memory corruption.
I've seen all the ways to do it manually through gdb, but I would like to actually set the watchpoint via some method in my code so I don't have to break into gdb, find out the address, set the watchpoint and then continue.
Something like:
#define SET_WATCHPOINT(addr) asm ("set break on hardware write %addr")
Set hardware watchpoint from child process.
#include <signal.h>
#include <syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/user.h>
enum {
DR7_BREAK_ON_EXEC = 0,
DR7_BREAK_ON_WRITE = 1,
DR7_BREAK_ON_RW = 3,
};
enum {
DR7_LEN_1 = 0,
DR7_LEN_2 = 1,
DR7_LEN_4 = 3,
};
typedef struct {
char l0:1;
char g0:1;
char l1:1;
char g1:1;
char l2:1;
char g2:1;
char l3:1;
char g3:1;
char le:1;
char ge:1;
char pad1:3;
char gd:1;
char pad2:2;
char rw0:2;
char len0:2;
char rw1:2;
char len1:2;
char rw2:2;
char len2:2;
char rw3:2;
char len3:2;
} dr7_t;
typedef void sighandler_t(int, siginfo_t*, void*);
int watchpoint(void* addr, sighandler_t handler)
{
pid_t child;
pid_t parent = getpid();
struct sigaction trap_action;
int child_stat = 0;
sigaction(SIGTRAP, NULL, &trap_action);
trap_action.sa_sigaction = handler;
trap_action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
sigaction(SIGTRAP, &trap_action, NULL);
if ((child = fork()) == 0)
{
int retval = EXIT_SUCCESS;
dr7_t dr7 = {0};
dr7.l0 = 1;
dr7.rw0 = DR7_BREAK_ON_WRITE;
dr7.len0 = DR7_LEN_4;
if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))
{
exit(EXIT_FAILURE);
}
sleep(1);
if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[0]), addr))
{
retval = EXIT_FAILURE;
}
if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[7]), dr7))
{
retval = EXIT_FAILURE;
}
if (ptrace(PTRACE_DETACH, parent, NULL, NULL))
{
retval = EXIT_FAILURE;
}
exit(retval);
}
waitpid(child, &child_stat, 0);
if (WEXITSTATUS(child_stat))
{
printf("child exit !0\n");
return 1;
}
return 0;
}
int var;
void trap(int sig, siginfo_t* info, void* context)
{
printf("new value: %d\n", var);
}
int main(int argc, char * argv[])
{
int i;
printf("init value: %d\n", var);
watchpoint(&var, trap);
for (i = 0; i < 100; i++) {
var++;
sleep(1);
}
return 0;
}
Based on user512106's great answer, I coded up a little "library" that someone might find useful:
It's on github at https://github.com/whh8b/hwbp_lib. I wish I could have commented directly on his answer, but I don't have enough rep yet.
Based on feedback from the community, I am going to copy/paste the relevant code here:
#include <stdio.h>
#include <stddef.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/prctl.h>
#include <stdint.h>
#include <errno.h>
#include <stdbool.h>
extern int errno;
enum {
BREAK_EXEC = 0x0,
BREAK_WRITE = 0x1,
BREAK_READWRITE = 0x3,
};
enum {
BREAK_ONE = 0x0,
BREAK_TWO = 0x1,
BREAK_FOUR = 0x3,
BREAK_EIGHT = 0x2,
};
#define ENABLE_BREAKPOINT(x) (0x1<<(x*2))
#define ENABLE_BREAK_EXEC(x) (BREAK_EXEC<<(16+(x*4)))
#define ENABLE_BREAK_WRITE(x) (BREAK_WRITE<<(16+(x*4)))
#define ENABLE_BREAK_READWRITE(x) (BREAK_READWRITE<<(16+(x*4)))
/*
* This function fork()s a child that will use
* ptrace to set a hardware breakpoint for
* memory r/w at _addr_. When the breakpoint is
* hit, then _handler_ is invoked in a signal-
* handling context.
*/
bool install_breakpoint(void *addr, int bpno, void (*handler)(int)) {
pid_t child = 0;
uint32_t enable_breakpoint = ENABLE_BREAKPOINT(bpno);
uint32_t enable_breakwrite = ENABLE_BREAK_WRITE(bpno);
pid_t parent = getpid();
int child_status = 0;
if (!(child = fork()))
{
int parent_status = 0;
if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))
_exit(1);
while (!WIFSTOPPED(parent_status))
waitpid(parent, &parent_status, 0);
/*
* set the breakpoint address.
*/
if (ptrace(PTRACE_POKEUSER,
parent,
offsetof(struct user, u_debugreg[bpno]),
addr))
_exit(1);
/*
* set parameters for when the breakpoint should be triggered.
*/
if (ptrace(PTRACE_POKEUSER,
parent,
offsetof(struct user, u_debugreg[7]),
enable_breakwrite | enable_breakpoint))
_exit(1);
if (ptrace(PTRACE_DETACH, parent, NULL, NULL))
_exit(1);
_exit(0);
}
waitpid(child, &child_status, 0);
signal(SIGTRAP, handler);
if (WIFEXITED(child_status) && !WEXITSTATUS(child_status))
return true;
return false;
}
/*
* This function will disable a breakpoint by
* invoking install_breakpoint is a 0x0 _addr_
* and no handler function. See comments above
* for implementation details.
*/
bool disable_breakpoint(int bpno)
{
return install_breakpoint(0x0, bpno, NULL);
}
/*
* Example of how to use this /library/.
*/
int handled = 0;
void handle(int s) {
handled = 1;
return;
}
int main(int argc, char **argv) {
int a = 0;
if (!install_breakpoint(&a, 0, handle))
printf("failed to set the breakpoint!\n");
a = 1;
printf("handled: %d\n", handled);
if (!disable_breakpoint(0))
printf("failed to disable the breakpoint!\n");
return 1;
}
I hope that this helps someone!
Will
In GDB, there are two types of watchpoints, hardware and software.
you can't implement easily software watchpoints: (cf. GDB Internals)
Software watchpoints are very slow, since gdb needs to single-step the program being debugged and test the value of the watched expression(s) after each instruction.
EDIT:
I'm still trying to understand what are hardware watchpoint.
for hardware breakpoints, this article gives some technics:
We want to watch reading from or writing into 1 qword at address 100005120h (address range 100005120h-100005127h)
lea rax, [100005120h]
mov dr0, rax
mov rax, dr7
and eax, not ((1111b shl 16) + 11b) ; mask off all
or eax, (1011b shl 16) + 1 ; prepare to set what we want
mov
dr7, rax ; set it finally
Done, now we can wait until code falls into the trap! After accessing any byte at memory range 100005120h-100005127h, int 1 will occur and DR6.B0 bit will be set to 1.
You can also take a look at GDB low-end files (eg, amd64-linux-nat.c) but it (certainly) involves 2 processes: 1/ the one you want to watch 2/a lightweight debugger who attaches to the first one with ptrace, and uses:
ptrace (PTRACE_POKEUSER, tid, __regnum__offset__, address);
to set and handle the watchpoint.
The program itself can supply commands to the GDB. You'll need a special shell script to run GDB though.
Copy this code into the file named untee, and execute chmod 755 untee
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: $0 PIPE | COMMAND"
echo "This script will read the input from both stdin and PIPE, and supply it to the COMMAND."
echo "If PIPE does not exist it will be created with mkfifo command."
exit 0
fi
PIPE="$1"
if [ \! -e "$PIPE" ]; then
mkfifo "$PIPE"
fi
if [ \! -p "$PIPE" ]; then
echo "File $PIPE does not exist or is not a named pipe" > /dev/stderr
exit 1
fi
# Open the pipe as a FD 3
echo "Waiting for $PIPE to be opened by another process" > /dev/stderr
exec 3<"$PIPE"
echo "$PIPE opened" > /dev/stderr
OPENED=true
while true; do
read -t 1 INPUT
RET=$?
if [ "$RET" = 0 ]; then
echo "$INPUT"
elif [ "$RET" -lt 128 ]; then
echo "stdin closed, exiting" > /dev/stderr
break
fi
if $OPENED; then
while read -t 1 -u 3 INPUT; do
RET=$?
if [ "$RET" = 0 ]; then
echo "$INPUT"
else
if [ "$RET" -lt 128 ]; then
echo "$PIPE closed, ignoring" > /dev/stderr
OPENED=false
fi
break
fi
done
fi
done
And now the C code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
void gdbCommand(const char *c)
{
static FILE * dbgpipe = NULL;
static const char * dbgpath = "/tmp/dbgpipe";
struct stat st;
if( !dbgpipe && stat(dbgpath, &st) == 0 && S_ISFIFO(st.st_mode) )
dbgpipe = fopen(dbgpath, "w");
if( !dbgpipe )
return;
fprintf(dbgpipe, "%s\n", c);
fflush(dbgpipe);
}
void gdbSetWatchpoint(const char *var)
{
char buf[256];
snprintf(buf, sizeof(buf), "watch %s", var);
gdbCommand("up"); /* Go up the stack from the kill() system call - this may vary by the OS, you may need to walk the stack more times */
gdbCommand("up"); /* Go up the stack from the gdbSetWatchpoint() function */
gdbCommand(buf);
gdbCommand("continue");
kill(getpid(), SIGINT); /* Make GDB pause our process and execute commands */
}
int subfunc(int *v)
{
*v += 5; /* GDB should pause after this line, and let you explore stack etc */
return v;
}
int func()
{
int i = 10;
printf("Adding GDB watch for var 'i'\n");
gdbSetWatchpoint("i");
subfunc(&i);
return i;
}
int func2()
{
int j = 20;
return j + func();
}
int main(int argc, char ** argv)
{
func();
func2();
return 0;
}
Copy that to the file named test.c, compile with command gcc test.c -O0 -g -o test then execute ./untee /tmp/dbgpipe | gdb -ex "run" ./test
This works on my 64-bit Ubuntu, with GDB 7.3 (older GDB versions might refuse to read commands from non-terminal)
If you happen to be using Xcode, you can achieve the required effect (automatic setting of watchpoints) by using an action on another breakpoint to set your watchpoint:
Set up a breakpoint somewhere where the variable you want to watch will be in scope that will be hit before you need to start watching the variable,
Right-click on the breakpoint and select Edit Breakpoint...,
Click on Add Action and add a Debugger Command with an LLDB command like: watchpoint set variable <variablename> (or if you're using GDB1, a command like: watch <variablename>),
Check the Automatically continue after evaluating actions checkbox.
1: GDB is no longer supported in more recent versions of Xcode, but I believe it is still possible to set it up manually.
Related
I want to debug an application where some threads seem to go into a deadlock situation in a production environment (I cannot debug, thus I need a meaningful log). I found boost::stacktrace::stacktrace(), but it dumps info for all threads.
Is it possible to limit the output to a specific thread?
If it is Linux specific you can use backtrace and backtrace_symbols to retrieve the backtrace for that specific thread.
I adapted this example from man backtrace to include a thread.
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread>
#define BT_BUF_SIZE 100
void printbt(void)
{
int j, nptrs;
void *buffer[BT_BUF_SIZE];
char **strings;
nptrs = backtrace(buffer, BT_BUF_SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
/* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
would produce similar output to the following: */
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);
}
static void myfunc2(void)
{
printbt();
}
void myfunc(int ncalls)
{
if (ncalls > 1)
myfunc(ncalls - 1);
else
myfunc2();
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "%s num-calls\n", argv[0]);
return 0;
}
std::thread th( myfunc, atoi(argv[1]) );
th.join();
}
You have to compile with -rdynamic to work
$ g++ -g3 -rdynamic test2.cpp -o /tmp/test2 -lpthread
Running it provides
$ /tmp/test2 3
backtrace() returned 13 addresses
/tmp/test2(_Z7printbtv+0x32) [0x55e2dbe5d37b]
/tmp/test2(+0x4451) [0x55e2dbe5d451]
/tmp/test2(_Z6myfunci+0x29) [0x55e2dbe5d47d]
/tmp/test2(_Z6myfunci+0x22) [0x55e2dbe5d476]
/tmp/test2(_Z6myfunci+0x22) [0x55e2dbe5d476]
/tmp/test2(_ZSt13__invoke_implIvPFviEJiEET_St14__invoke_otherOT0_DpOT1_+0x36) [0x55e2dbe5e0af]
/tmp/test2(_ZSt8__invokeIPFviEJiEENSt15__invoke_resultIT_JDpT0_EE4typeEOS3_DpOS4_+0x4a) [0x55e2dbe5dffd]
/tmp/test2(_ZNSt6thread8_InvokerISt5tupleIJPFviEiEEE9_M_invokeIJLm0ELm1EEEEvSt12_Index_tupleIJXspT_EEE+0x47) [0x55e2dbe5df4d]
/tmp/test2(_ZNSt6thread8_InvokerISt5tupleIJPFviEiEEEclEv+0x2b) [0x55e2dbe5deef]
/tmp/test2(_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFviEiEEEEE6_M_runEv+0x20) [0x55e2dbe5dec0]
/lib/x86_64-linux-gnu/libstdc++.so.6(+0xd6de4) [0x7f306312ede4]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x8609) [0x7f3063242609]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x43) [0x7f3062f6a133]
You can use __cxa_demangle to automatically demangle the symbols or you can simply use c++filt from gcc for that.
$ echo _ZSt13__invoke_implIvPFviEJiEET_St14__invoke_otherOT0_DpOT1_+0x36 | c++filt
void std::__invoke_impl<void, void (*)(int), int>(std::__invoke_other, void (*&&)(int), int&&)+0x36
$ echo _Z6myfunci+0x29 | c++filt
myfunc(int)+0x29
You can then go into gdb and look what line the offset 0x29 corresponds to inside the function myfunc(int)
All, the first part of my homework assignment is simply a demo program that I need to compile, and then modify. It was provided by the teacher, however I simply cannot get it to compile using g++. I will be creating a make file at the end of the assignment, but for the moment I am simply trying to test it out, and am having no luck. I've tried the most basic g++ command: g++ -o main TwoPipesTwoChildren.cpp . Can someone please help? I can't even get started on this until I can get this working.
// description: This program will execute "ls -ltr | grep 3376"
// by using a parent and child process
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv){
printf("TEST");
int status;
int childpid;
char *cat_args[] = {"ls", "-ltr", NULL};
char *grep_args[] = {"grep", "3376", NULL};
// create one pipe to send the output of "ls" process to "grep" process
int pipes[2];
pipe(pipes);
// fork the first child (to execute cat)
if((childpid = fork()) == -1)
{
perror("Error creating a child process");
exit(1);
}
// replace cat's stdout with write part of 1st pipe
if (childpid == 0)
{
dup2(pipes[1], 1);
printf("AFTER FORK CHILD");
//close all pipes (very important!); end we're using was safely copied
close(pipes[0]);
close(pipes[1]);
execvp(*cat_args, cat_args);
exit(0);
}
else
{
// replace grep's stdin with read end of 1st pipe
dup2(pipes[0], 0);
close(pipes[0]);
close(pipes[1]);
execvp(*grep_args, grep_args);
}
return (0);
}
I was running a program (valgrind, actually) on my Ubuntu machine, and had redirected both stdout and stderr to different files. I was surprised to see a short message appear on the screen -- how is that possible? How could I do that myself in a C++ program?
EDIT: Here's the command I used, and the output:
$ valgrind ./myprogram > val.out 2> val.err
*** stack smashing detected ***: ./myprogram terminated
EDIT2: Playing with it a little more, it turns out that myprogram, not valgrind, is causing the message to be printed, and as answered below, it looks like gcc stack smashing detection code is printing to /dev/tty
It is not written by valgrind but rather glibc and your ./myprogram is using glibc:
#define _PATH_TTY "/dev/tty"
/* Open a descriptor for /dev/tty unless the user explicitly
requests errors on standard error. */
const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
if (on_2 == NULL || *on_2 == '\0')
fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
fd = STDERR_FILENO;
...
written = WRITEV_FOR_FATAL (fd, iov, nlist, total);
Below are some relevant parts of glibc:
void
__attribute__ ((noreturn))
__stack_chk_fail (void)
{
__fortify_fail ("stack smashing detected");
}
void
__attribute__ ((noreturn))
__fortify_fail (msg)
const char *msg;
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminated\n",
msg, __libc_argv[0] ?: "<unknown>");
}
/* Abort with an error message. */
void
__libc_message (int do_abort, const char *fmt, ...)
{
va_list ap;
int fd = -1;
va_start (ap, fmt);
#ifdef FATAL_PREPARE
FATAL_PREPARE;
#endif
/* Open a descriptor for /dev/tty unless the user explicitly
requests errors on standard error. */
const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
if (on_2 == NULL || *on_2 == '\0')
fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
fd = STDERR_FILENO;
...
written = WRITEV_FOR_FATAL (fd, iov, nlist, total);
The message is most probably from GCC's stack protector feature or from glib itself. If it's from GCC, it is output using the fail() function, which directly opens /dev/tty:
fd = open (_PATH_TTY, O_WRONLY);
_PATH_TTY is not really standard, but SingleUnix actually demands that /dev/tty exists.
Here is some sample code that does exactly what was asked (thanks to earlier answers pointing me in the right direction). Both are compiled with g++, and will print a message to the screen even when stdout and stderr are redirected.
For Linux (Ubuntu 14):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main( int, char *[]) {
printf("This goes to stdout\n");
fprintf(stderr, "This goes to stderr\n");
int ttyfd = open("/dev/tty", O_RDWR);
const char *msg = "This goes to screen\n";
write(ttyfd, msg, strlen(msg));
}
For Windows 7, using MinGW:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <conio.h>
void writeConsole( const char *s) {
while( *s) {
putch(*(s++));
}
}
int main( int, char *[]) {
printf("This goes to stdout\n");
fprintf(stderr, "This goes to stderr\n");
writeConsole( "This goes to screen\n");
}
Both tools are available over here: https://github.com/ninjablocks/433Utils/tree/master/RPi_utils
I really want a simple interface to manage my 433mhz devices. but i can't find a good one.
So I have worked all day now trying to make a wrapper for nodejs to the RCSwitch class. with 2 simple methods
- send[code]
- recieve[callback[code]]
I get this error when i try to make a new instance of the RCSwitch class.
node: symbol lookup error:
/root/nodemodule/example/build/Release/kaku.node:
undefined symbol: _ZN8RCSwitchC1Ev
It compiles perfectly with node-gyp but when I execute node it fails.
Now I use exec to execute sendCommand with the code. (UGLY I Know)
And I tried to make the RFSniffer work like this:
./RFSniffer > rfsniffer.log
.Then tail -f the rfsniffer.log
But RFSniffer wont give me any data.
So my question is can anybody help me to get RFsniffer working with tail -f
Or even beter can someone help me fix the c++ addon for nodejs:)
Here is the wrapper code:
#include "RCSwitch.h"
#include <node.h>
#include <v8.h>
using namespace v8;
Handle<Value> CodeSend(const Arguments& args) {
HandleScope scope;
int PIN = 0;
RCSwitch mySwitch = RCSwitch();
mySwitch.enableTransmit(PIN);
mySwitch.send(args[0]->IntegerValue(), 24);
return scope.Close(True());
}
Handle<Value> CodeRecieve(const Arguments& args) {
HandleScope scope;
// Entry check
if (args.Length() != 2) {
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
return scope.Close(Undefined());
}
Local<String> name= args[0]->ToString();
Local<String> msg = name;
Local<Function> cb = Local<Function>::Cast(args[1]);
const unsigned argc = 1;
Local<Value> argv[argc] = { Local<Value>::New(msg) };
cb->Call(Context::GetCurrent()->Global(), argc, argv);
return scope.Close(Undefined());
}
extern "C" {
static void init(Handle<Object> target) {
if( wiringPiSetup() == -1 ) {
ThrowException( Exception::TypeError( String::New( "rcswitch: GPIO initialization failed" ) ) );
return;
}
NODE_SET_METHOD(target, "Send", CodeSend);
NODE_SET_METHOD(target, "Recieve", CodeRecieve);
}
NODE_MODULE(kaku, init);
}
nodejs code:
var addon = require('./build/Release/kaku');
console.log(addon.Send(1234));
addon.Recieve(1234, function (val) {
console.log(val);
});
I had the same problem than you and the reason why ./RFSniffer > rfsniffer.log doesn't work is that printf() function in RFSniffer code is not flushed.
Try with this source code :
/*
RF_Sniffer
Hacked from http://code.google.com/p/rc-switch/
by #justy to provide a handy RF code sniffer
*/
#include "RCSwitch.h"
#include <stdlib.h>
#include <stdio.h>
RCSwitch mySwitch;
int main(int argc, char *argv[]) {
// This pin is not the first pin on the RPi GPIO header!
// Consult https://projects.drogon.net/raspberry-pi/wiringpi/pins/
// for more information.
int PIN = 2;
if(wiringPiSetup() == -1)
return 0;
mySwitch = RCSwitch();
mySwitch.enableReceive(PIN); // Receiver on inerrupt 0 => that is pin #2
while(1) {
if (mySwitch.available()) {
int value = mySwitch.getReceivedValue();
if (value == 0) {
printf("Unknown encoding");
} else {
printf("Received %i\n", mySwitch.getReceivedValue() );
}
fflush(stdout); // Add this line to flush the previous printf()
mySwitch.resetAvailable();
}
}
exit(0);
}
And if you run the RFSniffer tool with sudo permission, you can execute with :
sudo ./RFSniffer | sudo tee rfsniffer.log
OR
sudo sh -c './RFSniffer >> rfsniffer.log'
I work on a linux platform and I use g++ with the above program that copies a function from the code area to the data area. How do I change protection of data segment in order to allow me to execute the copied function ?
The code is bellow:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define Return asm volatile("pop %rbp; retq; retq; retq; retq; retq;")
int64_t funcEnd=0xc35dc3c3c3c3c35d;
constexpr int maxCode=0x800;
int8_t code[maxCode];
void testCode(void){
int a=8,b=7;
a+=b*a;
Return;
}
typedef void (*action)(void);
int main(int argc, char **argv)
{
action a=&testCode;
testCode();
int8_t *p0=(int8_t*)a,*p=p0,*p1=p0+maxCode;
for(;p!=p1;p++)
if ( (*(int64_t*)p)==funcEnd ) break;
if(p!=p1){
p+=sizeof(int64_t);
printf("found\n");
memcpy(&code,(void*)a,p-(int8_t*)a);
((action)&code)();
}
printf("returning 0\n");
return 0;
}
It depends if you are trying to do this statically (at build-time), or at dynamically (at run-time).
Build-time
You need to tell GCC to put your blob in a section that is executable. We use __attribute__((section)), and this trick to specify the attributes of the section when we create it.
Run-time
TL;DR: Jump to the end of my answer, where I use mmap.
Although others might be questioning why you'd want do allow something like this at run-time, keep in mind that this is exactly what a VM with a JIT compiler (e.g. Java VM, .NET CLR, etc.) do when emitting native code.
You need to change the memory protections of the memory where you're trying to execute. We do that with mprotect(addr, PROT_EXEC). Note that addr must be aligned to the page size of your platform. On x86, the page size is 4K. We use aligned_alloc to guarantee this alignment.
Example (of both):
#define _ISOC11_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h> /* mprotect() */
__attribute__((section(".my_executable_blob,\"awx\",#progbits#")))
static uint8_t code[] = {
0xB8,0x2A,0x00,0x00,0x00, /* mov eax,0x2a */
0xC3, /* ret */
};
int main(void)
{
int (*func)(void);
/* Execute a static blob of data */
func = (void*)code;
printf("(static) code returned %d\n", func());
/* Execute a dynamically-allocated blob of data */
void *p = aligned_alloc(0x1000, sizeof(code));
if (!p) {
fprintf(stderr, "aligned_alloc() failed\n");
return 2;
}
memcpy(p, code, sizeof(code));
if (mprotect(p, sizeof(code), PROT_EXEC) < 0) {
perror("mprotect");
return 2;
}
func = p;
printf("(dynamic) code returned %d\n", func());
return 0;
}
Output:
$ ./a.out
(static) code returned 42
(dynamic) code returned 42
SELinux Impact
Note that this puts your executable code on the heap which might be a bit dangerous. SELinux on my CentOS 7 machine actually denied the mprotect call:
SELinux is preventing /home/jreinhart/so/a.out from using the execheap access on a process.
***** Plugin allow_execheap (53.1 confidence) suggests ********************
If you do not think /home/jreinhart/so/a.out should need to map heap memory that is both writable and executable.
Then you need to report a bug. This is a potentially dangerous access.
So I had to temporarily sudo setenforce 0 to get this to work.
I'm not sure why, however, because looking in /proc/[pid]/maps, the pages are clearly marked only as executable, not as "writable and executable" as SELinux indicated. If I move the memcpy after the mprotect, my process segfaults, because I'm trying to write to non-writable memory. So it seems SELinux is being a bit too over-zealous here.
Use mmap instead
Instead of mprotecting a region of the heap (allocated with aligned_alloc), it is more straightforward to use mmap. This also avoids any issues with SELinux, as we're not trying to execute on the heap.
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h> /* mmap() */
static uint8_t code[] = {
0xB8,0x2A,0x00,0x00,0x00, /* mov eax,0x2a */
0xC3, /* ret */
};
int main(void)
{
void *p = mmap(NULL, sizeof(code), PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (p==MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
return 2;
}
memcpy(p, code, sizeof(code));
int (*func)(void) = p;
printf("(dynamic) code returned %d\n", func());
pause();
return 0;
}
The final solution
The mmap solution is good, but it doesn't provide us any safety; our mmaped region of code is readable, writable, and executable. It would be better to only allow the memory to be writable while we're putting our code in place, then making it executable only. The following code does just that:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h> /* mmap(), mprotect() */
static uint8_t code[] = {
0xB8,0x2A,0x00,0x00,0x00, /* mov eax,0x2a */
0xC3, /* ret */
};
int main(void)
{
const size_t len = sizeof(code);
/* mmap a region for our code */
void *p = mmap(NULL, len, PROT_READ|PROT_WRITE, /* No PROT_EXEC */
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (p==MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
return 2;
}
/* Copy it in (still not executable) */
memcpy(p, code, len);
/* Now make it execute-only */
if (mprotect(p, len, PROT_EXEC) < 0) {
fprintf(stderr, "mprotect failed to mark exec-only\n");
return 2;
}
/* Go! */
int (*func)(void) = p;
printf("(dynamic) code returned %d\n", func());
pause();
return 0;
}