From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25748 invoked by alias); 24 Aug 2017 14:15:07 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 23748 invoked by uid 89); 24 Aug 2017 14:15:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM,KAM_LOTSOFHASH,RCVD_IN_DNSWL_LOW,RCVD_IN_SORBS_SPAM,SPF_PASS autolearn=ham version=3.3.2 spammy=insecure, crucial, 16.5, 5555 X-HELO: mail-qt0-f181.google.com Received: from mail-qt0-f181.google.com (HELO mail-qt0-f181.google.com) (209.85.216.181) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 24 Aug 2017 14:15:00 +0000 Received: by mail-qt0-f181.google.com with SMTP id 69so3657506qtb.1 for ; Thu, 24 Aug 2017 07:15:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=wIfv7ed3vzGvLMpJHNPzAZVNCOVNVtXCmy/RbbBcUAc=; b=fQLUusNIv6EXBJ6rVkOHzT663ag0QE0l4UocC0lgcMYwRQkBeyC2eefodXwQJaZ9H3 MRaBS3ZdhxdddkpewcopSAgCEAgC/p2VwDAyZO+IadOsVF8XYM/4d5DyJCr+dtORR+LY /MTgMjKCFuRbHezgRPT5IjVzYgt7fAJ8MT6+M9YHQq4jvfZlXn6z2Bj2EsTtKWP92oEs qaxgoa1hH5w/buvf2dju/jybLaYWCqmg7Sgq3KLqYU1lup2lmA1/C6FnzelfT9Rli1wK GcApAfWHBl5NeXMZuK1z6SjpLW//qN6S5sJX0VXw/DEPkNyiBuSHIslz9vMlaOLX0xwz OC0Q== X-Gm-Message-State: AHYfb5iDDYqpmyYWyaEe0aiBFUHz9VWquil9I1C5jMi+k9G8WC8Of/kT vRGWFnxEItrH6CRd0zly7y8idb3sww== X-Received: by 10.200.43.175 with SMTP id m44mr8212390qtm.195.1503584098947; Thu, 24 Aug 2017 07:14:58 -0700 (PDT) MIME-Version: 1.0 Received: by 10.237.43.226 with HTTP; Thu, 24 Aug 2017 07:14:58 -0700 (PDT) In-Reply-To: <402cb282-9cd1-2725-f6de-ec5f9eb15e0d@redhat.com> References: <1503549910-24770-1-git-send-email-jon@ringle.org> <402cb282-9cd1-2725-f6de-ec5f9eb15e0d@redhat.com> From: Jon Ringle Date: Thu, 24 Aug 2017 14:15:00 -0000 Message-ID: Subject: Re: [PATCH v2] gdbserver: linux_low: elf_64_file_p cache results To: Pedro Alves Cc: gdb-patches@sourceware.org, Jon Ringle Content-Type: text/plain; charset="UTF-8" X-SW-Source: 2017-08/txt/msg00467.txt.bz2 On Thu, Aug 24, 2017 at 5:26 AM, Pedro Alves wrote: > Hi Jon, > > On 08/24/2017 05:45 AM, jon@ringle.org wrote: > >> The problem lied in the fact that the function elf_64_file_p() (call on >> line 7184), was returning -1 because it could not open the file (with errno >> set to EACCESS). This was because the inferior's code was dropping root >> privileges and no longer was able to read the file. > > I feel like I'm missing something. If it's the inferior that > is dropping privileges, how can that affect gdbserver? It's gdbserver > that opens the file, not the inferior. > > It'd be nice to have a testcase for this. Would it be possible to come > up with a small reproducer? > I learned something while coming up with a small reproducer. The real program I'm debugging is a systemd service and has a CapabilityBoundingSet. The CapabilityBoundingSet turns out to be a crucial point for reproducing. I setup a systemd service: $ cat /lib/systemd/system/droproot-test.service [Unit] Description=gdbserver droproot test service [Service] Type=simple ExecStart=/home/jringle/build/gdbserver/gdbserver :5555 /home/jringle/git/droproot-test/droproot-test jringle Restart=on-success CapabilityBoundingSet=CAP_SETGID CAP_SETUID Here's droproot-test.c: $ cat -n droproot-test.c 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 /* Drop root privileges and chroot if necessary */ 11 void droproot(const char *username, const char *chroot_dir) 12 { 13 struct passwd *pw = NULL; 14 15 if (!username) 16 { 17 fprintf(stderr, "%s: no username given", __func__); 18 return; 19 } 20 21 if (chroot_dir && !username) 22 { 23 fprintf(stderr, "%s: Chroot without dropping root is insecure\n", __func__); 24 exit(1); 25 } 26 27 pw = getpwnam(username); 28 if (pw) 29 { 30 if (chroot_dir) 31 { 32 if (chroot(chroot_dir) != 0 || chdir ("/") != 0) 33 { 34 fprintf(stderr, "%s: Couldn't chroot/chdir to '%.64s': %s\n", __func__, 35 chroot_dir, strerror(errno)); 36 exit(1); 37 } 38 } 39 if (initgroups(pw->pw_name, pw->pw_gid) != 0 || 40 setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) 41 { 42 fprintf(stderr, "%s: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n", __func__, 43 username, 44 (unsigned long)pw->pw_uid, 45 (unsigned long)pw->pw_gid, 46 strerror(errno)); 47 exit(1); 48 } 49 } 50 else 51 { 52 fprintf(stderr, "%s: Couldn't find user '%.32s'\n", __func__, 53 username); 54 exit(1); 55 } 56 } 57 58 int main(int argc, char *argv[]) 59 { 60 int uid = getuid(); 61 62 printf("Before droproot uid is %d\n", uid); 63 fflush(stdout); 64 if (uid == 0) 65 { 66 droproot(argv[1], NULL); 67 } 68 69 uid = getuid(); 70 printf("After droproot uid is %d\n", uid); 71 fflush(stdout); 72 73 return 0; 74 } If you break on line 66, gdbserver will be able to read the r_debug table just fine, but step to next line after root has been dropped, it can't: $ gdb droproot-test GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: . Find the GDB manual and other documentation resources online at: . For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from droproot-test...done. (gdb) target remote :5555 Remote debugging using :5555 Reading /lib/ld-linux.so.2 from remote target... warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead. Reading /lib/ld-linux.so.2 from remote target... Reading symbols from target:/lib/ld-linux.so.2...Reading /lib/b9332ff9d20717877cd3ff483d9426825cdef5.debug from remote target... Reading /lib/.debug/b9332ff9d20717877cd3ff483d9426825cdef5.debug from remote target... (no debugging symbols found)...done. 0xf7fd9a20 in ?? () from target:/lib/ld-linux.so.2 (gdb) tb 66 Temporary breakpoint 1 at 0x804861f: file droproot-test.c, line 66. (gdb) cont Continuing. Reading /lib32/libc.so.6 from remote target... Reading /lib32/333186c6b532511a68d16aca4c61422eb772da.debug from remote target... Reading /lib32/.debug/333186c6b532511a68d16aca4c61422eb772da.debug from remote target... Temporary breakpoint 1, main (argc=2, argv=0xffffde54) at droproot-test.c:66 66 droproot(argv[1], NULL); (gdb) info sharedlibrary From To Syms Read Shared Object Library 0xf7fd9860 0xf7ff271d Yes (*) target:/lib/ld-linux.so.2 0xf7e18750 0xf7f4186d Yes (*) target:/lib32/libc.so.6 (*): Shared library is missing debugging information. (gdb) n Reading /lib32/libnss_compat.so.2 from remote target... Reading /lib32/libnsl.so.1 from remote target... Reading /lib32/6a2d2c3683ee8c596fb834c373a010a527cf23.debug from remote target... Reading /lib32/.debug/6a2d2c3683ee8c596fb834c373a010a527cf23.debug from remote target... Reading /lib32/b31e7cb309897e1db3b4abc464de2e324e5606.debug from remote target... Reading /lib32/.debug/b31e7cb309897e1db3b4abc464de2e324e5606.debug from remote target... Reading /lib32/libnss_nis.so.2 from remote target... Reading /lib32/libnss_files.so.2 from remote target... Reading /lib32/3730cbd17cd03a91793441cf426924c3efe048.debug from remote target... Reading /lib32/.debug/3730cbd17cd03a91793441cf426924c3efe048.debug from remote target... Reading /lib32/54fdb9da826ae5d6cbc2554bbadd512b7b639d.debug from remote target... Reading /lib32/.debug/54fdb9da826ae5d6cbc2554bbadd512b7b639d.debug from remote target... 69 uid = getuid(); (gdb) info sharedlibrary From To Syms Read Shared Object Library 0xf7fd9860 0xf7ff271d Yes (*) target:/lib/ld-linux.so.2 (*): Shared library is missing debugging information. (gdb) Here's the gdbserver output: $ sudo systemctl restart droproot-test && journalctl -o cat -u droproot-test -f Started gdbserver droproot test service. Process /home/jringle/git/droproot-test/droproot-test created; pid = 18180 Listening on port 5555 Remote debugging from host 127.0.0.1 Before droproot uid is 0 gdbserver: Corrupted shared library list: 0x0 != 0x580b8c8d4cca6b >> This patch implements a cache per file in the elf_64_file_p() function so >> that it remembers the results of a previous query for the same filename. >> >> Since it seems that c++ is now accepted in gdb, the cache was implemented >> using std::map > > Doesn't look correct, since it assumes that the 64-bit-ness > of "/proc/PID/exe" stays constant for the lifetime of gdbserver, > which is certainly false. With "gdbserver --multi", a single gdbserver can > stay around debugging multiple processes for an undeterminate amount of time. > After the current process PID exits, nothing prevents the kernel from > reusing PID for another process. > > Also, we need to clear the cache when the inferior process execs, > since a 32-bit process can well exec a 64-bit process, and vice-versa. > > If caching is the right approach, then it seems to me that it'd be > much simpler/efficient to make it a new 'bool is_elf64;' field of > struct process_info_private. That sounds like a good idea. I'll look into implementing something along those lines... -Jon