Is it safe to call execl on a anonymous elf file? - linux

First create an anonymous memory block by
int fd = memfd_create("", MFD_CLOEXEC);
Note that I pass MFD_CLOEXEC flag.
Then I copy elf file content into this anonymous memory.
The elf is executed like this:
char cmd[128];
sprintf(cmd, "/proc/self/fd/%i", fd);
execl(cmd, "dummy", NULL);
MFD_CLOEXEC means that fd will be closed after execl, but here execl need to load elf content from fd. I do a simple test and it seems OK. But I am not sure it is safe or not.
update:
#define _GNU_SOURCE
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <stdio.h>
extern uint8_t foo_data[] asm("_binary_htop_start");
extern uint8_t foo_data_size[] asm("_binary_htop_size");
extern uint8_t foo_data_end[] asm("_binary_htop_end");
int main(int argc, char **argv)
{
int exefd = memfd_create("", MFD_CLOEXEC);
printf("%p %d %ld\n", foo_data, exefd, write(exefd, foo_data, foo_data_end-foo_data));
char * const vv[] = {"htopp", NULL};
//execveat(exefd, NULL, vv, NULL, AT_EMPTY_PATH);
exefd = syscall(__NR_execveat, exefd, NULL, vv, NULL, AT_EMPTY_PATH);
perror("");
return 0;
}
I try with execveat but fail. syscall set errno to "Bad address", don't know the reason. elf content is generated by objcopy.

It's perfectly fine with real binaries (like ELF files), whether statically or dynamically linked.
MFD_CLOEXEC will not work with executable scripts (eg. files starting with #! /bin/sh). You'll have to omit that flag and leave the fd open in that case.
Instead of your sprintf / execl trick, you should look into using execveat(fd, "", argv, env, AT_EMPTY_PATH) (which unfortunately has the same problem with executable scripts opened with O_CLOEXEC, but doesn't rely on a /proc fs being mounted).
And of course, you should always use (void*)0 instead of NULL with variadic functions like execl() ;-)

Related

Crash system when the module is running

I need to write a module that creates a file and outputs an inscription with a certain frequency. I implemented it. But when this module is running, at some point the system crashes and no longer turns on.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
#define BUF_LEN 255
#define TEXT "Hello from kernel mod\n"
int g_timer_interval = 10000;
static struct file *i_fp;
struct timer_list g_timer;
loff_t offset = 0;
char buff[BUF_LEN + 1] = TEXT;
void timer_rest(struct timer_list *timer)
{
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
i_fp = filp_open("/home/hajol/Test.txt", O_RDWR | O_CREAT, 0644);
kernel_write(i_fp, buff, strlen(buff), &offset);
filp_close(i_fp, NULL);
}
static int __init kernel_init(void)
{
timer_setup(&g_timer, timer_rest, 0);
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
return 0;
}
static void __exit kernel_exit(void)
{
pr_info("Ending");
del_timer(&g_timer);
}
module_init(kernel_init);
module_exit(kernel_exit);
When the system crashes, you should get a very detailed error message from the kernel, letting you know where and why this happened (the "oops" message):
Read that error message
Read it again
Understand what it means (this often requires starting over from step 1 a couple of times :-) )
One thing that jumps out at me is that you're not going any error checking on the return value of filp_open. So you could very well be feeding a NULL pointer (or error pointer) into kernel_write.

Why proc_read(), which is a function related to /proc in Linux, is called "repeatedly" until it returns 0?

In the book Operating System Concepts, it designs a kernel module, the module seems to create an additional entry named hello in the /proc file system in Linux, the module code is shown below, then it uses cat /proc/hello command, it says "Each time the /proc/hello file is read, the proc_read() function is called repeatedly until it returns 0", I can't understand why proc_read() is called repeatedly, also I don't know who is the caller of the function proc_read().
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#define BUFFER_SIZE 128
#define PROC_NAME "hello"
ssize_t proc_read(struct file *file, char _user *usr_buf, size_t count, loff_t *pos);
static struct file_operations proc_ops = {
.owner = THIS MODULE,
.read = proc_read,
};
/* This function is called when the module is loaded. */
int proc_init(void)
{
/* creates the /proc/hello entry */
proc_create(PROC_NAME, 0666, NULL, &proc_ops);
return 0;
}
/* This function is called when the module is removed. */
void proc_exit(void)
{
/* removes the /proc/hello entry */
remove_proc_entry(PROC_NAME, NULL);
}

Reserve a virtual address range in dynamic linker

Is there a way to reserve a particular range of virtual address space in a process memory map to stop ld.so (dynamic linker) from loading any shared objects into that range. Something like a system wide configuration option that reserves a particular range.
I want to be able to map a region of shared memory into exactly the same virtual address space in several processes so that my pointers in my data-structures will still work. I know I could redesign to use offsets instead of pointers but I don't want to do that.
You can do this by creating a simple shared object and running it via LD_PRELOAD. Compile the following code:
#include <sys/mman.h> // for mmap, munmap, and related constants
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void my_program_init() __attribute__((constructor));
void *const address = ((void*)0x10000000);
const int size = 0x1000;
void my_program_init() {
printf("Hello from my_program_init!\n");
int fd = shm_open("/mysharedmem", O_CREAT | O_RDWR, 0666);
if (fd == -1) {
printf("shm_open\n");
return;
}
if (ftruncate(fd, size) == -1) {
printf("ftruncate\n");
return;
}
void* shared_mem = mmap(address, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
if (shared_mem == MAP_FAILED) {
printf("mmap\n");
return;
}
return;
}
with the following options:
gcc -shared -fPIC -o libmylib.so myso.c
Then you can run your program like this:
LD_PRELOAD=./libmylib.so ./your_prog
The so is then loaded before any runtime linking happens in your program. The function in the so tagged as a constructor runs immediately and uses mmap to reserve the memory you want for your shared block.
You can see this working with the following example program:
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
int main() {
char *data = (char*)0x10000000;
const char *message = "Hello, world!\n";
memcpy(data, message, strlen(message));
printf("Wrote %ld bytes to memory at address %p %s\n", strlen(message), data, data);
return 0;
}
If you run this without the LD_PRELOAD it will segfault, but if you include the preload the shared block of memory is available as expected.
$ LD_PRELOAD=./libmylib.so ./a.out
Hello from my_program_init!
Wrote 14 bytes to memory at address 0x10000000 Hello, world!
You can construct your own tests to validate that the memory block is actually shared but the easiest check is to recompile the test program again without the memcpy and see that the string is still there from the first run of the program.

Can FD_ISSET be called with a descriptor that was not added to the select set?

I'm debugging a select loop that normally works OK but dies with segmentation fault under heavy load. I've figured out that the program is sometimes invoking FD_ISSET() for a (correct) descriptor that was not added to the select set. Like in a following snippet:
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void die(const char* msg)
{
fprintf(stderr, "fatal %s", msg);
exit(1);
}
int main(void)
{
FILE* file = fopen("/tmp/test", "r");
if (file == NULL)
die("fopen");
int file_fd = fileno(file);
fd_set read_fds;
int max_fd = 0;
FD_ZERO(&read_fds);
// Only stdin is added to read_fds.
FD_SET(0, &read_fds);
if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) < 0)
die("select");
if (FD_ISSET(0, &read_fds))
printf("Can read from 0");
// !!! Here FD_ISSET is called with a valid descriptor that was
// not added to read_fds.
if (FD_ISSET(file_fd, &read_fds))
printf("Can read from file_fd");
return 0;
}
It is obvious that the check marked with !!! should never return true, but is it possible that it can be the cause of the SEGFAULT? When I run this snippet under valgrind, no errors are reported, but when I run my load test under valgrind I'm ocasionnaly seing errors like:
==25513== Syscall param select(writefds) points to uninitialised byte(s)
==25513== at 0x435DD2D: ___newselect_nocancel (syscall-template.S:82)
FD_ISSET() tests to see if a file descriptor is a part of the set read_fds. This means that FD_ISSET should not cause the segmentation fault.
Try checking for errno value set prior to calling the FD_ISSET. The select should be causing the segfault.
Also check that the file_fd value isn't greater than FD_MAX.

linux ptrace() get function information

i want to catch information from user defined function using ptrace() calls.
but function address is not stable(because ASLR).
how can i get another program's function information like gdb programmatically?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <dlfcn.h>
#include <errno.h>
void error(char *msg)
{
perror(msg);
exit(-1);
}
int main(int argc, char **argv)
{
long ret = 0;
void *handle;
pid_t pid = 0;
struct user_regs_struct regs;
int *hackme_addr = 0;
pid = atoi(argv[1]);
ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
if(ret<0)
{
error("ptrace() error");
}
ret = waitpid(pid, NULL, WUNTRACED);
if(ret<0)
{
error("waitpid ()");
}
ret = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
if(ret<0)
{
error("GETREGS error");
}
printf("EIP : 0x%x\n", (int)regs.eip);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return 0;
}
ptrace is a bit ugly, but it can be useful.
Here's a ptrace example program; it's used to make I/O-related system calls pause.
http://stromberg.dnsalias.org/~strombrg/slowdown/
You could of course also study gdb, but ISTR it's pretty huge.
You might also check out strace and ltrace, perhaps especially ltrace since it lists symbols.
HTH
You probably want to call a function that resides in a specific executable (probably, a shared object). So, first, you will have to find the base address this executable is mapped on using
/proc/pid/maps
After that, you need to find the local offset of the function you are interested in, and you can do this in two ways:
Understand the ELF file format (Linux native executable format), and searching the desired function using the mapped file (This requires some specialty)
Using a ready to use elfparser (probably readelf tool) to get the function offset under the executable. Note that you will have to figure out the real local offset since this tool usually gives you the address as if the executable was mapped to a specific address

Resources