Fix an overflow bug in __get_elf_note().

Seen in the wild on ILP32.

There was also a bug where we'd only check the first note in a segment,
which hasn't mattered in practice so far, but seems worth fixing while
we're here (and makes the condition a bit clearer anyway).

Also lift the strlen() out of the loop.

Bug: https://issuetracker.google.com/380356872
Change-Id: I458efb197116f68722ba7fca96fe376fdb6c8352
diff --git a/libc/bionic/elf_note.cpp b/libc/bionic/elf_note.cpp
index d5cd5de..9cc6b21 100644
--- a/libc/bionic/elf_note.cpp
+++ b/libc/bionic/elf_note.cpp
@@ -38,31 +38,34 @@
     return false;
   }
 
+  size_t note_name_len = strlen(note_name) + 1;
+
   ElfW(Addr) p = note_addr;
   ElfW(Addr) note_end = p + phdr_note->p_memsz;
-
   while (p + sizeof(ElfW(Nhdr)) <= note_end) {
+    // Parse the note and check it's structurally valid.
     const ElfW(Nhdr)* note = reinterpret_cast<const ElfW(Nhdr)*>(p);
     p += sizeof(ElfW(Nhdr));
     const char* name = reinterpret_cast<const char*>(p);
-    p += align_up(note->n_namesz, 4);
+    if (__builtin_add_overflow(p, align_up(note->n_namesz, 4), &p)) {
+      return false;
+    }
     const char* desc = reinterpret_cast<const char*>(p);
-    p += align_up(note->n_descsz, 4);
+    if (__builtin_add_overflow(p, align_up(note->n_descsz, 4), &p)) {
+      return false;
+    }
     if (p > note_end) {
-      break;
-    }
-    if (note->n_type != note_type) {
-      continue;
-    }
-    size_t note_name_len = strlen(note_name) + 1;
-    if (note->n_namesz != note_name_len || strncmp(note_name, name, note_name_len) != 0) {
-      break;
+      return false;
     }
 
-    *note_hdr = note;
-    *note_desc = desc;
-
-    return true;
+    // Is this the note we're looking for?
+    if (note->n_type == note_type &&
+        note->n_namesz == note_name_len &&
+        strncmp(note_name, name, note_name_len) == 0) {
+      *note_hdr = note;
+      *note_desc = desc;
+      return true;
+    }
   }
   return false;
 }