)]}'
{
  "commit": "8a89ddbda2ecb41be0f12142e5d4b95c7bd5a138",
  "tree": "6b9b95c6b028265c02d63f884067b51068a15988",
  "parents": [
    "707ed39ac5cb255f656b2947b50c8273c8ad1d80"
  ],
  "author": {
    "name": "Pedro Alves",
    "email": "pedro@palves.net",
    "time": "Tue Sep 14 19:01:37 2021 +0100"
  },
  "committer": {
    "name": "Pedro Alves",
    "email": "pedro@palves.net",
    "time": "Fri Nov 05 17:24:21 2021 +0000"
  },
  "message": "Avoid /proc/pid/mem races (PR 28065)\n\nPR 28065 (gdb.threads/access-mem-running-thread-exit.exp intermittent\nfailure) shows that GDB can hit an unexpected scenario -- it can\nhappen that the kernel manages to open a /proc/PID/task/LWP/mem file,\nbut then reading from the file returns 0/EOF, even though the process\nhasn\u0027t exited or execed.\n\n\"0\" out of read/write is normally what you get when the address space\nof the process the file was open for is gone, because the process\nexeced or exited.  So when GDB gets the 0, it returns memory access\nfailure.  In the bad case in question, the process hasn\u0027t execed or\nexited, so GDB fails a memory access when the access should have\nworked.\n\nGDB has code in place to gracefully handle the case of opening the\n/proc/PID/task/LWP/mem just while the LWP is exiting -- most often the\nopen fails with EACCES or ENOENT.  When it happens, GDB just tries\nopening the file for a different thread of the process.  The testcase\nis written such that it stresses GDB\u0027s logic of closing/reopening the\n/proc/PID/task/LWP/mem file, by constantly spawning short lived\nthreads.\n\nHowever, there\u0027s a window where the kernel manages to find the thread,\nbut the thread exits just after and clears its address space pointer.\nIn this case, the kernel creates a file successfully, but the file\nends up with no address space associated, so a subsequent read/write\nreturns 0/EOF too, just like if the whole process had execed or\nexited.  This is the case in question that GDB does not handle.\n\nOleg Nesterov gave this suggestion as workaround for that race:\n\n    gdb can open(/proc/pid/mem) and then read (say) /proc/pid/statm.\n    If statm reports something non-zero, then open() was \"successfull\".\n\nI think that might work.  However, I didn\u0027t try it, because I realized\nwe have another nasty race that that wouldn\u0027t fix.\n\nThe other race I realized is that because we close/reopen the\n/proc/PID/task/LWP/mem file when GDB switches to a different inferior,\nthen it can happen that GDB reopens /proc/PID/task/LWP/mem just after\na thread execs, and before GDB has seen the corresponding exec event.\nI.e., we can open a /proc/PID/task/LWP/mem file accessing the\npost-exec address space thinking we\u0027re accessing the pre-exec address\nspace.\n\nA few months back, Simon, Oleg and I discussed a similar race:\n\n  [Bug gdb/26754] Race condition when resuming threads and one does an exec\n  https://sourceware.org/bugzilla/show_bug.cgi?id\u003d26754\n\nThe solution back then was to make the kernel fail any ptrace\noperation until the exec event is consumed, with this kernel commit:\n\n commit dbb5afad100a828c97e012c6106566d99f041db6\n Author:     Oleg Nesterov \u003coleg@redhat.com\u003e\n AuthorDate: Wed May 12 15:33:08 2021 +0200\n Commit:     Linus Torvalds \u003ctorvalds@linux-foundation.org\u003e\n CommitDate: Wed May 12 10:45:22 2021 -0700\n\n     ptrace: make ptrace() fail if the tracee changed its pid unexpectedly\n\nThis however, only applies to ptrace, not to the /proc/pid/mem file\nopening case.  Also, even if it did apply to the file open case, we\nwould want to support current kernels until such a fix is more wide\nspread anyhow.\n\nSo all in all, this commit gives up on the idea of only ever keeping\none /proc/pid/mem file descriptor open.  Instead, make GDB open a\n/proc/pid/mem per inferior, and keep it open until the inferior exits,\nis detached or execs.  Make GDB open the file right after the inferior\nis created or is attached to or forks, at which point we know the\ninferior is stable and stopped and isn\u0027t thus going to exec, or have a\nthread exit, and so the file open won\u0027t fail (unless the whole process\nis SIGKILLed from outside GDB, at which point it doesn\u0027t matter\nwhether we open the file).\n\nThis way, we avoid both races described above, at the expense of using\nmore file descriptors (one per inferior).\n\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d28065\nChange-Id: Iff943b95126d0f98a7973a07e989e4f020c29419\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "cada889c5348eb5c8841aee8f2d2438d61b58ec1",
      "old_mode": 33188,
      "old_path": "gdb/linux-nat.c",
      "new_id": "f8f728481ea76c77351d14eb39a1a40dfca8281b",
      "new_mode": 33188,
      "new_path": "gdb/linux-nat.c"
    },
    {
      "type": "modify",
      "old_id": "4c2e2b776e416ac90018b9f2f5741339c263694d",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp",
      "new_id": "7c2ea5d40f7737cdb520a4972b4e10f95b14b2f5",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp"
    }
  ]
}
