Why does the dynamic library (SO) of the CP overwriting process cause coredump?

Source: Internet
Author: User

> For reprinting, please specify the Source: piao2010's blog, the drifting code. Thank you! Pai_^

> Link to this article: Why does the dynamic library (SO) of the process overwritten by CP cause coredump?

The question behind the previous blog "Linux shared library (SO) Dynamic Loading and upgrade": Why does the dynamic library (SO) of the CP overwrite process (running program) Cause coredump?
The previous analysis only caused the tragedy because the inode number is not changed when CP overwrites the so file, but the root cause is not found. As a result, I began to find and learn how to implement dynamic links in Linux and the common operations of GDB. I found a key article when searching for relevant information. I found that I could use GDB to perform relevant tests under the guidance of the author's ideas.
Modify the code in the test. c file.

? View code C

 
12345678910111213
#include<stdio.h> void test1(void){    int j=0;    printf("test1:j=%d\n", j);    return ;} void test2(void){    int j=1;    printf("test2:j=%d\n", j);    return ;}

Execute gcc-FPIC-shared-O libtest. So test. C-g to generate the shared library file (note that this time we bring the-G debugging information)
Slightly modify the main process file main. c

? View code C

 
12345678910111213141516171819202122232425262728293031323334353637383940414243
# Include <stdio. h> # include <dlfcn. h>/* This header file */INT main () {void * lib_handle; void (* fn1) (void); void (* FN2) (void ); char * error; lib_handle = dlopen ("libtest. so ", rtld_lazy); If (! Lib_handle) {fprintf (stderr, "% s \ n", dlerror (); return 1 ;}fn1 = dlsym (lib_handle, "test1 "); if (error = dlerror ())! = NULL) {fprintf (stderr, "% s \ n", error); return 1;} printf ("fn1: 0x % x \ n", fn1 ); fn1 (); FN2 = dlsym (lib_handle, "Test2"); If (error = dlerror ())! = NULL) {fprintf (stderr, "% s \ n", error); return 1;} printf ("FN2: 0x % x \ n", FN2 ); FN2 (); dlclose (lib_handle); Return 0 ;}

Run gcc-O main. C-LDL-g to generate the binary file main, which also carries debugging information.
Then use GDB to load main for debugging,

? View code C

 
GDB-Q mainreading symbols from/root/SO/main... done. (GDB) B 27 // in main. row C sets the breakpoint 1 at 0x80485fc: file main. c, line 27. (GDB) L 27 // display code 22 return 1; 23} 2425 printf ("fn1: 0x % x \ n", fn1); 26 27 fn1 (); 2829 FN2 = dlsym (lib_handle, "Test2"); 30 if (error = dlerror ())! = NULL) 31 {(GDB) r // run the program starting program:/root/SO/main fn1: 0x2c1450 breakpoint 1, main () at main. c: 27 // interrupt in our preset 27 Rows 27 fn1 (); missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.i686 // use CP in another terminal to convert libtest2.so (just libtest. so) overwrite libtest. so (GDB) S // One-Step follow-up function fn1 () Implementation test1 () at test. c: 44 Int J = 0; (GDB) S5 printf ("test1: J = % d \ n", J); // execute test. c 4th line Int J = 0; no problem because no external symbols are introduced. (GDB) s program passed ed signal SIGSEGV, segmentation fault. // run test. c 5th line printf ("test1: J = % d \ n", J); problem, because printf is an external symbol 0x0000035a in ?? () (GDB) BT // print stack information #0 0x0000035a in ?? () #1 0x002c147e in test1 () at test. c: 5 // test. row C 5th is printf ("test1: J = % d \ n", J); #2 0x08048602 in main () at main. c: 27 (GDB)

For comparison, test. the second line of C is annotated, and the main. C also commented out from lines 29 to 39 (coredump will also appear if you execute the dlsym function after so overwrite, so comment out the FN2-related operations first ), after re-compilation, the test showed that coredump would not occur this time, indicating that the problem was indeed caused by the external symbol printf.

In addition, if you set the breakpoint to the dlsym function, you can check the effect.

? View code C

 
GDB-Q mainreading symbols from/root/SO/main... done. (GDB) B dlsymbreakpoint 1 at 0x8048434 (GDB) rstarting program:/root/SO/main breakpoint 1, 0x001_d26 in dlsym () from/lib/libdl. so.2missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.i686 // use CP in another terminal to convert libtest2.so (just libtest. so) overwrite libtest. so (GDB) Ssingle stepping until exit from function dlsym, which has no line number information. program received signal SIGSEGV, segmentation fault.0x00119531 in check_match.8616 () from/lib/ld-linux.so.2 (GDB) BT #0 0x00119531 in check_match.8616 () from/lib/ld-linux.so.2 #1 0x00119d64 in do_lookup_x () from/lib/ld-linux.so.2 #2 0x00119f5a in _ dl_lookup_symbol_x () from/lib/ld-linux.so.2 #3 0x00252560 in do_sym () from/lib/libc. so.6 #4 0x0025295a in _ dl_sym () from/lib/libc. so.6 #5 0x000000de8 in dlsym_doit () from/lib/libdl. so.2 #6 0x0011e966 in _ dl_catch_error () from/lib/ld-linux.so.2 #7 0x0013203c in _ dlerror_run () from/lib/libdl. so.2 #8 0x001_d7c in dlsym () from/lib/libdl. so.2 #9 0x080485ab in main () at main. c: 18

Download glibc source code view related functions do_lookup_x: dl-lookup.c File

? View code C

 
129130131132133134135136137138139140
      /* Nested routine to check whether the symbol matches.  */      const ElfW(Sym) *      __attribute_noinline__      check_match (const ElfW(Sym) *sym)      {unsigned int stt = ELFW(ST_TYPE) (sym->st_info);assert (ELF_RTYPE_CLASS_PLT == 1);if (__builtin_expect ((sym->st_value == 0 /* No value.  */       && stt != STT_TLS)      || (type_class & (sym->st_shndx == SHN_UNDEF)),      0))  return NULL;

View related function check_match: tst-rxspencer.c File

? View code C

 
173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
static intcheck_match (regmatch_t *rm, int idx, const char *string,     const char *match, const char *fail){  if (match[0] == '-' && match[1] == '\0')    {      if (rm[idx].rm_so == -1 && rm[idx].rm_eo == -1)return 0;      printf ("%s rm[%d] unexpectedly matched\n", fail, idx);      return 1;    }   if (rm[idx].rm_so == -1 || rm[idx].rm_eo == -1)    {      printf ("%s rm[%d] unexpectedly did not match\n", fail, idx);      return 1;    }   if (match[0] == '@')    {      if (rm[idx].rm_so != rm[idx].rm_eo){  printf ("%s rm[%d] not empty\n", fail, idx);  return 1;}       if (strncmp (string + rm[idx].rm_so, match + 1, strlen (match + 1) ?: 1)){  printf ("%s rm[%d] not matching %s\n", fail, idx, match);  return 1;}      return 0;    }   if (rm[idx].rm_eo - rm[idx].rm_so != strlen (match)      || strncmp (string + rm[idx].rm_so, match,  rm[idx].rm_eo - rm[idx].rm_so))    {      printf ("%s rm[%d] not matching %s\n", fail, idx, match);      return 1;    }   return 0;}

The experiment results are consistent with the author's conclusion, so I will reference them directly:
1. When the application opens so through dlopen, the kernel loads so to the process address space through MMAP, which corresponds to several pages in VMA.
2. In this process, loader will parse the external symbols referenced in so, such as malloc printf, into a real virtual address.
3. When so is overwritten by CP and is exactly trunc, the kernel will purge the so file in the virtual page.
4. When you run the code in so, because there is no actual data in the physical memory (only available in the virtual storage space), a page disconnection occurs.
5. kernel copies a copy from the so file to the memory, a) but the global symbol table is not parsed. When it is called, segment fault and B are generated) if the required file offset is greater than the new so address range, a bus error occurs.

Therefore, if the same so is used to overwrite
A) if so is dependent on external symbols, coredump
B) if so does not depend on external symbols, it's a good luck and won't be coredump.

References:

Http://blog.sina.com.cn/s/blog_622a99700100pjv3.html

Http://www.ibm.com/developerworks/cn/linux/l-dynlink/index.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.