Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using dlopen, how can I cope with changes to the library file I have loaded?

Tags:

c++

linux

dlopen

I have a program written in C++ which uses dlopen to load a dynamic library (Linux, i386, .so). When the library file is subsequently modified, my program tends to crash. This is understandable, since presumably the file is simply mapped into memory.

My question is: other than simply creating myself a copy of the file and dlopening that, is there way for me to load a shared object which is safe against subsequent modifications, or any way to recover from modifications to a shared object that I have loaded?

Clarification: The question is not "how can I install a new library without crashing the program", it is "if someone who I don't control is copying libraries around, is it possible for me to defend against that?"

like image 405
kdt Avatar asked Oct 15 '09 17:10

kdt


People also ask

Where does Dlopen look library?

Otherwise, dlopen() will search for the library in the following order: A colon-separated list of directories in the user's LD_LIBRARY_PATH environment variable. The list of libraries specified in /etc/ld.

Can you Dlopen an executable?

On some ELF systems (notably Linux), you can dlopen() PIE executables. When using GCC, just compile the executable with -fpie or -fPIE , and link it with -pie , and export the appropriate symbols using --dynamic-list or -rdynamic (explained in more detail in this other SO answer.

What library is Dlopen in?

dlopen() The function dlopen() loads the dynamic shared object (shared library) file named by the null-terminated string filename and returns an opaque "handle" for the loaded object. This handle is employed with other functions in the dlopen API, such as dlsym(3), dladdr(3), dlinfo(3), and dlclose().


1 Answers

If you rm the library prior to installing the new one, I think your system will keep the inode allocated, the file open, and your program running. (And when your program finally exits, then the mostly-hidden-but-still-there file resources are released.)

Update: Ok, post-clarification. The dynamic linker actually completely "solves" this problem by passing the MAP_COPY flag, if available, to mmap(2). However, MAP_COPY does not exist on Linux and is not a planned future feature. Second best is MAP_DENYWRITE, which I believe the loader does use, and which is in the Linux API, and which Linux used to do. It errors-out writes while a region is mapped. It should still allow an rm and replace. The problem here is that anyone with read-access to a file can map it and block writes, which opens a local DoS hole. (Consider /etc/utmp. There is a proposal to use the execute permission bit to fix this.)

You aren't going to like this, but there is a trivial kernel patch that will restore MAP_DENYWRITE functionality. Linux still has the feature, it just clears the bit in the case of mmap(2). You have to patch it in code that is duplicated per-architecture, for ia32 I believe the file is arch/x86/ia32/sys_ia32.c.

asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
                            unsigned long prot, unsigned long flags,
                            unsigned long fd, unsigned long pgoff)
{
        struct mm_struct *mm = current->mm;
        unsigned long error;
        struct file *file = NULL;

        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); // fix this line to not clear MAP_DENYWRITE

This should be OK as long as you don't have any malicious local users with credentials. It's not a remote DoS, just a local one.

like image 162
DigitalRoss Avatar answered Sep 21 '22 06:09

DigitalRoss