[v2,1/1] nss: return early in DB reload-and-get if newfstatat fails (BZ #28752)

Message ID 20220314175316.3239120-2-sam@gentoo.org
State Superseded
Headers
Series nss: return early in DB reload-and-get if newfstatat fails (BZ #28752) |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent
dj/TryBot-32bit success Build for i686

Commit Message

Sam James March 14, 2022, 5:53 p.m. UTC
  In some circumstances, the __stat64_time64() call in
nss_database_check_reload_and_get() might fail (via e.g. newfstatat
being filtered by seccomp in parent).

We have to check its return value to avoid an out of bounds access later
on if the call failed.

This manifests as Firefox crashing at runtime when e.g. glib is
compiled with FAM support, which ends up taking this NSS path.

Bug: https://sourceware.org/pipermail/libc-help/2021-December/006061.html
Bug: https://bugs.gentoo.org/828070
Suggested-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Signed-off-by: Sam James <sam@gentoo.org>
---
 nss/nss_database.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
  

Patch

diff --git a/nss/nss_database.c b/nss/nss_database.c
index d56c5b798d..a0522ea7d2 100644
--- a/nss/nss_database.c
+++ b/nss/nss_database.c
@@ -424,17 +424,21 @@  nss_database_check_reload_and_get (struct nss_database_state *local,
      errors here are very unlikely, but the chance that we're entering
      a container is also very unlikely, so we err on the side of both
      very unlikely things not happening at the same time.  */
-  if (__stat64_time64 ("/", &str) != 0
-      || (local->root_ino != 0
-	  && (str.st_ino != local->root_ino
-	      ||  str.st_dev != local->root_dev)))
-    {
+  if (__stat64_time64 ("/", &str) != 0) {
+    __libc_lock_unlock (local->lock);
+    return false;
+  }
+
+  if (local->root_ino != 0 && (str.st_ino != local->root_ino
+                              || str.st_dev != local->root_dev))
+   {
       /* Change detected; disable reloading and return current state.  */
       atomic_store_release (&local->data.reload_disabled, 1);
       *result = local->data.services[database_index];
       __libc_lock_unlock (local->lock);
       return true;
     }
+
   local->root_ino = str.st_ino;
   local->root_dev = str.st_dev;
   __libc_lock_unlock (local->lock);