Self-modifying code does not work under advanced optimization - linux

I tried to write a self-modifying code. (Refer to the link https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/) The self-modifying code works when there is no optimization (-o0)
gcc -O0 smc.c -o smc
Calling foo...
i: 1
Calling foo...
i: 42
while when the optimization level increases (-O1-O2-O3..) Self-modifying code no longer works.
gcc -O3 smc.c -o smc
Calling foo...
i: 1
Calling foo...
i: 1
Is it possible to make self-modifying code work with -O3 level optimization, and what should I do?
The program is as follows:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
void foo(void);
int change_page_permissions_of_address(void *addr);
int main(void) {
void *foo_addr = (void*)foo;
// Change the permissions of the page that contains foo() to read, write, and execute
// This assumes that foo() is fully contained by a single page
if(change_page_permissions_of_address(foo_addr) == -1) {
fprintf(stderr, "Error while changing page permissions of foo(): %s\n", strerror(errno));
return 1;
}
// Call the unmodified foo()
puts("Calling foo...");
foo();
// Change the immediate value in the addl instruction in foo() to 42
unsigned char *instruction = (unsigned char*)foo_addr + 22;
// Notice that 22 here is the offset that I compiled. Different compilations and machine offsets may vary.
*instruction = 0x2A;
// Call the modified foo()
puts("Calling foo...");
foo();
return 0;
}
void foo(void) {
int i=0;
i++;
printf("i: %d\n", i);
}
int change_page_permissions_of_address(void *addr) {
// Move the pointer to the page boundary
int page_size = getpagesize();
addr -= (unsigned long)addr % page_size;
if(mprotect(addr, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
{
return -1;
}
return 0;
}

Related

Get function from x64 instruction pointers?

This is an exercise that I want to implement in real code
I send a signal to my app (x86-64 linux). My app then executes code that walks the stack and prints out instruction pointers. I'm not sure if I want only the last few or everything to main. Anyway, I'm releasing an optimized binary without debug information. I strip symbols before its distributed.
I was wondering, how do I translate it back? I don't need to translate it in the app. I can use the machine I build to go from rip's to functions. I was thinking maybe I should also distribute one with debug information and maybe have the user be able to see the function+line but I think line will be unlikely if its optimized well
Another problem I have is my code doesn't seem to walk past the signal function. backtrace figures it out but I'm trying to do this without libc. Here's some code
#include <signal.h>
#include <cstdio>
typedef unsigned long long u64;
int mybacktrace();
#include <execinfo.h>
#include <unistd.h>
void print_stacktrace(void) {
size_t size;
enum Constexpr { MAX_SIZE = 1024 };
void *array[MAX_SIZE];
size = backtrace(array, MAX_SIZE);
backtrace_symbols_fd(array, size, STDOUT_FILENO);
}
void mysig(int signo) {
mybacktrace();
_exit(1);
}
int mybacktrace() {
u64*p;
p = (u64*)((u64)&p + 16); //seems to work correctly
for (int i = 0; i < 10 && (u64)p >= 1<<16; i++)
{
printf("%d %p\n", i, p[1]);
p = (u64*)(p[0]);
}
print_stacktrace(); return 0;
return 0;
}
int test()
{
return mybacktrace();
}
int main(int argc, char *argv[])
{
signal(SIGILL, mysig);
test();
__builtin_trap();
return 0;
}

Overriding default malloc library in Ubuntu [duplicate]

I wrote my own malloc and free and compiled them in a shared library. I LD_PRELOAD that library with my program. In this way would my program always use my custom malloc and free or are there cases where it is not so. I've heard that gcc has built in malloc and free too. Is it possible that the glibc that came with my gcc is using the builtin malloc and free.
Secondly, I notice that when I run my program, I'm seeing the free function call more often than the malloc/calloc calls (98 to 16). I don't do any memory allocation myself (except in one place), so all allocation is being done by standard library functions that I use. And also note I'm using pthread in my program. If you want to know, my program looks like this.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#define NUM_THREADS 8
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
int sum;
float total = 1;
extern int __did_libc_start_main;
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
pthread_mutex_lock( &m );
sum++;
total *= total + tid * 0.097891313423578;
printf( "p%d, tid%d, total = %g, start = %d!\n", getpid(), tid, total, 0 );
pthread_mutex_unlock( &m );
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
char * p;
char * m;
fork();
p = (char*)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
p[0] = 78;
printf( "p = %p, p[0] = %d, pid = %d!\n", p, p[0], getpid() );
m = (char*)malloc( 80 );
printf( "m = %p!\n", m );
#if 1
for(t=0; t<NUM_THREADS; t++)
{
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
for(t=0; t<NUM_THREADS; t++)
pthread_join(threads[t], NULL);
printf( "\n\nTotal = %g\n\n", total );
/* Last thing that main() should do */
pthread_exit(NULL);
#endif
printf( "\n\n%d: Done without major problems\n\n", getpid() );
return 0;
}
Using LD_PRELOAD to override malloc etc. is expected to work; this is how e.g. DUMA works.
In addition to malloc, calloc and free, make sure you override realloc, memalign and valloc. In addition you might need to override C++ new, new[], delete and delete[].
See Overriding 'malloc' using the LD_PRELOAD mechanism for an example of how to do this right.

writing my first exploit in linux

How can I modify the source code in the func( ) so that the address to which the program returns after executing func () is changed in such a manner that the instruction printf("first print\n”) is skipped. Use the pointer *ret defined in func() to modify the return address appropriately in order to achieve this.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(char *str)
{
char buffer[24];
int *ret;
strcpy(buffer,str);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("One argument needed.\n");
exit(0);
}
int x;
x = 0;
func(argv[1]);
x = 1;
printf("first print\n");printf("second print\n");
}
As sherrellbc noted, a program's exploits are usually written without modifying its source code. But if you want, inserting these two lines into func() may do:
ret = (int *)&str; // point behind saved return address
ret[-1] += 12; // or however many code bytes are to be skipped

How do I use ioctl() to manipulate my kernel module?

So I'm trying to write a kernel module that uses the linux/timer.h file. I got it to work inside just the module, and now I am trying to get it to work from a user program.
Here is my kernel module:
//Necessary Includes For Device Drivers.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/ioctl.h>
#define DEVICE_NAME "mytimer"
#define DEVICE_FILE_NAME "mytimer"
#define MAJOR_NUM 61
#define MINOR_NUM 0
MODULE_LICENSE("Dual BSD/GPL");
static struct timer_list my_timer;
struct file_operations FileOps =
{
//No File Operations for this timer.
};
//Function to perform when timer expires.
void TimerExpire(int data)
{
printk("Timer Data: %d\n", data);
}
//Function to set up timers.
void TimerSetup(void)
{
setup_timer(&my_timer, TimerExpire, 5678);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000));
}
//Module Init and Exit Functions.
int init_module(void)
{
int initResult = register_chrdev(MAJOR_NUM, "mytimer", &FileOps);
if (initResult < 0)
{
printk("Cannot obtain major number %d\n", MAJOR_NUM);
return initResult;
}
printk("Loading MyTimer Kernel Module...\n");
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(MAJOR_NUM, "mytimer");
printk("Unloading MyTimer Kernel Module...\n");
}
More specifically, I want my user program to call the TimerSetup() function. I know that I'll need to use ioctl() but I'm not sure how to specify in my MODULE FILE that TimerSetup() should be callable via ioctl().
Also, my second question: I was able to insmod my module and also mknod into /dev/mytimer with the correct major number. But when I tried to open() it so that I can get the file descriptor from it, it kept returning -1, which I'm assuming is wrong. I made sure the permissions were fine (in fact, I made it 777 just to be sure)... It still doesn't work... Is there something I'm missing?
Here is the user program just in case:
#include <stdio.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/mytimer", "r");
printf("fd: %d\n", fd);
return 0;
}
The example code you need can be found in drivers/watchdog/softdog.c (from Linux 2.6.33 at the time this was written), which illustrates proper file operations as well as how to permit userland to fill a structure with ioctl().
It's actually a great, working tutorial for anyone who needs to write trivial character device drivers.
I dissected softdog's ioctl interface when answering my own question, which may be helpful to you.
Here's the gist of it (though far from exhaustive) ...
In softdog_ioctl() you see a simple initialization of struct watchdog_info that advertises functionality, version and device information:
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = "Software Watchdog",
};
We then look at a simple case where the user just wants to obtain these capabilities:
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
... which of course, will fill the corresponding userspace watchdog_info with the initialized values above. If copy_to_user() fails, -EFAULT is returned which causes the corresponding userspace ioctl() call to return -1 with a meaningful errno being set.
Note, the magic requests are actually defined in linux/watchdog.h , so that the kernel and userspace share them:
#define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
#define WDIOC_GETSTATUS _IOR(WATCHDOG_IOCTL_BASE, 1, int)
#define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
#define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int)
#define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
#define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int)
#define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
#define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
#define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
WDIOC obviously signifying "Watchdog ioctl"
You can easily take that a step further, having your driver do something and place the result of that something in the structure and copy it to userspace. For instance, if struct watchdog_info also had a member __u32 result_code. Note, __u32 is just the kernel's version of uint32_t.
With ioctl(), the user passes the address of an object, be it a structure, integer, whatever to the kernel expecting the kernel to write its reply in an identical object and copy the results to the address that was provided.
The second thing you are going to need to do is make sure your device knows what to do when someone opens, reads from it, writes to it, or uses a hook like ioctl(), which you can easily see by studying softdog.
Of interest is:
static const struct file_operations softdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = softdog_write,
.unlocked_ioctl = softdog_ioctl,
.open = softdog_open,
.release = softdog_release,
};
Where you see the unlocked_ioctl handler going to ... you guessed it, softdog_ioctl().
I think you might be juxtaposing a layer of complexity that really doesn't exist when dealing with ioctl(), it really is that simple. For that same reason, most kernel developers frown on new ioctl interfaces being added unless they are absolutely necessary. Its just too easy to lose track of the type that ioctl() is going to fill vs the magic you use to do it, which is the primary reason that copy_to_user() fails often resulting in the kernel rotting with hordes of userspace processes stuck in disk sleep.
For a timer, I agree, ioctl() is the shortest path to sanity.
You are missing a .open function pointer in your file_operations structure to specify the function to be called when a process attempts to open the device file. You will need to specify a .ioctl function pointer for your ioctl function as well.
Try reading through The Linux Kernel Module Programming Guide, specifically chapters 4 (Character Device Files) and 7 (Talking to Device Files).
Chapter 4 introduces the file_operations structure, which holds pointers to functions defined by the module/driver that perform various operations such as open or ioctl.
Chapter 7 provides information on communicating with a module/drive via ioctls.
Linux Device Drivers, Third Edition is another good resource.
Minimal runnable example
Tested in a fully reproducible QEMU + Buildroot environment, so might help others get their ioctl working. GitHub upstream:
kernel module |
shared header |
userland.
The most annoying part was understanding that some low ids are hijacked: ioctl is not called if cmd = 2 , you have to use _IOx macros.
Kernel module:
#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include "ioctl.h"
MODULE_LICENSE("GPL");
static struct dentry *dir;
static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
void __user *arg_user;
union {
int i;
lkmc_ioctl_struct s;
} arg_kernel;
arg_user = (void __user *)argp;
pr_info("cmd = %x\n", cmd);
switch (cmd) {
case LKMC_IOCTL_INC:
if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) {
return -EFAULT;
}
pr_info("0 arg = %d\n", arg_kernel.i);
arg_kernel.i += 1;
if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) {
return -EFAULT;
}
break;
case LKMC_IOCTL_INC_DEC:
if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) {
return -EFAULT;
}
pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j);
arg_kernel.s.i += 1;
arg_kernel.s.j -= 1;
if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) {
return -EFAULT;
}
break;
default:
return -EINVAL;
break;
}
return 0;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = unlocked_ioctl
};
static int myinit(void)
{
dir = debugfs_create_dir("lkmc_ioctl", 0);
/* ioctl permissions are not automatically restricted by rwx as for read / write,
* but we could of course implement that ourselves:
* https://stackoverflow.com/questions/29891803/user-permission-check-on-ioctl-command */
debugfs_create_file("f", 0, dir, NULL, &fops);
return 0;
}
static void myexit(void)
{
debugfs_remove_recursive(dir);
}
module_init(myinit)
module_exit(myexit)
Shared header between the kernel module and userland:
ioctl.h
#ifndef IOCTL_H
#define IOCTL_H
#include <linux/ioctl.h>
typedef struct {
int i;
int j;
} lkmc_ioctl_struct;
#define LKMC_IOCTL_MAGIC 0x33
#define LKMC_IOCTL_INC _IOWR(LKMC_IOCTL_MAGIC, 0, int)
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)
#endif
Userland:
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "../ioctl.h"
int main(int argc, char **argv)
{
int fd, arg_int, ret;
lkmc_ioctl_struct arg_struct;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file>");
return EXIT_FAILURE;
}
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
/* 0 */
{
arg_int = 1;
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d\n", arg_int);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
puts("");
/* 1 */
{
arg_struct.i = 1;
arg_struct.j = 1;
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d %d\n", arg_struct.i, arg_struct.j);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
close(fd);
return EXIT_SUCCESS;
}

msemaphore on linux?

AIX (and HPUX if anyone cares) have a nice little feature called msemaphores that make it easy to synchronize granular pieces (e.g. records) of memory-mapped files shared by multiple processes. Is anyone aware of something comparable in linux?
To be clear, the msemaphore functions are described by following the related links here.
POSIX semaphores can be placed in memory shared between processes, if the second argument to sem_init(3), "pshared", is true. This seems to be the same as what msem does.
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
int main() {
void *shared;
sem_t *sem;
int counter, *data;
pid_t pid;
srand(time(NULL));
shared = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_SHARED, -1, 0);
sem_init(sem = shared, 1, 1);
data = shared + sizeof(sem_t);
counter = *data = 0;
pid = fork();
while (1) {
sem_wait(sem);
if (pid)
printf("ping>%d %d\n", data[0] = rand(), data[1] = rand());
else if (counter != data[0]) {
printf("pong<%d", counter = data[0]);
sleep(2);
printf(" %d\n", data[1]);
}
sem_post(sem);
if (pid) sleep(1);
}
}
This is a pretty dumb test, but it works:
$ cc -o test -lrt test.c
$ ./test
ping>2098529942 315244699
pong<2098529942 315244699
pong<1195826161 424832009
ping>1195826161 424832009
pong<1858302907 1740879454
ping>1858302907 1740879454
ping>568318608 566229809
pong<568318608 566229809
ping>1469118213 999421338
pong<1469118213 999421338
ping>1247594672 1837310825
pong<1247594672 1837310825
ping>478016018 1861977274
pong<478016018 1861977274
ping>1022490459 935101133
pong<1022490459 935101133
...
Because the semaphore is shared between the two processes, the pongs don't get interleaved data from the pings despite the sleeps.
This can be done using POSIX shared-memory mutexes:
pthread_mutexattr_t attr;
int pshared = PTHREAD_PROCESS_SHARED;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, &pshared);
pthread_mutex_init(&some_shared_mmap_structure.mutex, &attr);
pthread_mutexattr_destroy(&attr);
Now you can unlock and lock &some_shared_mmap_structure.mutex using ordinary pthread_mutex_lock() etc calls, from multiple processes that have it mapped.
Indeed, you can even implement the msem API in terms of this: (untested)
struct msemaphore {
pthread_mutex_t mut;
};
#define MSEM_LOCKED 1
#define MSEM_UNLOCKED 0
#define MSEM_IF_NOWAIT 1
msemaphore *msem_init(msemaphore *msem_p, int initialvalue) {
pthread_mutex_attr_t attr;
int pshared = PTHREAD_PROCESS_SHARED;
assert((unsigned long)msem_p & 7 == 0); // check alignment
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, &pshared); // might fail, you should probably check
pthread_mutex_init(&msem_p->mut, &attr); // never fails
pthread_mutexattr_destroy(&attr);
if (initialvalue)
pthread_mutex_lock(&attr);
return msem_p;
}
int msem_remove(msemaphore *msem) {
return pthread_mutex_destroy(&msem->mut) ? -1 : 0;
}
int msem_lock(msemaphore *msem, int cond) {
int ret;
if (cond == MSEM_IF_NOWAIT)
ret = pthread_mutex_trylock(&msem->mut);
else
ret = pthread_mutex_lock(&msem->mut);
return ret ? -1 : 0;
}
int msem_unlock(msemaphore *msem, int cond) {
// pthreads does not allow us to directly ascertain whether there are
// waiters. However, a unlock/trylock with no contention is -very- fast
// using linux's pthreads implementation, so just do that instead if
// you care.
//
// nb, only fails if the mutex is not initialized
return pthread_mutex_unlock(&msem->mut) ? -1 : 0;
}
Under Linux, you may be able to achieve what you want with SysV shared memory; quick googling turned up this (rather old) guide that may be of help.

Resources