Require vendor users and groups to start with vendor_

Require that users and groups found in /vendor/etc/{passwd,group}
start with vendor_.  This is needed to compliance with Treble as
without this prefix, it is possible for a new system image to create a
user/group name that a vendor has already used, causing a collision.

Bug: 79528966
Test: new unit test
Change-Id: I07500641e165f41526a8101592d83fa174e7a711
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 952058f..1de8fc5 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -46,8 +46,8 @@
 #include "generated_android_ids.h"
 #include "grp_pwd_file.h"
 
-static PasswdFile vendor_passwd("/vendor/etc/passwd");
-static GroupFile vendor_group("/vendor/etc/group");
+static PasswdFile vendor_passwd("/vendor/etc/passwd", "vendor_");
+static GroupFile vendor_group("/vendor/etc/group", "vendor_");
 
 // POSIX seems to envisage an implementation where the <pwd.h> functions are
 // implemented by brute-force searching with getpwent(3), and the <grp.h>
diff --git a/libc/bionic/grp_pwd_file.cpp b/libc/bionic/grp_pwd_file.cpp
index 37493a7..d19b41e 100644
--- a/libc/bionic/grp_pwd_file.cpp
+++ b/libc/bionic/grp_pwd_file.cpp
@@ -30,9 +30,12 @@
 
 #include <fcntl.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 
+#include <async_safe/log.h>
+
 #include "private/ErrnoRestorer.h"
 
 // This file mmap's /*/etc/passwd and /*/etc/group in order to return their contents without any
@@ -189,7 +192,8 @@
 
 }  // namespace
 
-MmapFile::MmapFile(const char* filename) : filename_(filename) {
+MmapFile::MmapFile(const char* filename, const char* required_prefix)
+    : filename_(filename), required_prefix_(required_prefix) {
   lock_.init(false);
 }
 
@@ -266,6 +270,18 @@
 
   while (line_beginning < end) {
     line_beginning = ParseLine(line_beginning, end, line->fields, line->kNumFields);
+    // To comply with Treble, users/groups from the vendor partition need to be prefixed with
+    // vendor_.
+    if (required_prefix_ != nullptr) {
+      if (strncmp(line->fields[0], required_prefix_, strlen(required_prefix_)) != 0) {
+        char name[kGrpPwdBufferSize];
+        CopyFieldToString(name, line->fields[0], sizeof(name));
+        async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                              "Found user/group name '%s' in '%s' without required prefix '%s'",
+                              name, filename_, required_prefix_);
+        continue;
+      }
+    }
     if (predicate(line)) return true;
   }
 
@@ -303,7 +319,8 @@
   });
 }
 
-PasswdFile::PasswdFile(const char* filename) : mmap_file_(filename) {
+PasswdFile::PasswdFile(const char* filename, const char* required_prefix)
+    : mmap_file_(filename, required_prefix) {
 }
 
 bool PasswdFile::FindById(uid_t id, passwd_state_t* passwd_state) {
@@ -318,7 +335,8 @@
   return mmap_file_.FindByName(name, &passwd_line) && passwd_line.ToPasswdState(passwd_state);
 }
 
-GroupFile::GroupFile(const char* filename) : mmap_file_(filename) {
+GroupFile::GroupFile(const char* filename, const char* required_prefix)
+    : mmap_file_(filename, required_prefix) {
 }
 
 bool GroupFile::FindById(gid_t id, group_state_t* group_state) {
diff --git a/libc/bionic/grp_pwd_file.h b/libc/bionic/grp_pwd_file.h
index 048cd82..29d75f4 100644
--- a/libc/bionic/grp_pwd_file.h
+++ b/libc/bionic/grp_pwd_file.h
@@ -37,7 +37,7 @@
 
 class MmapFile {
  public:
-  MmapFile(const char* filename);
+  MmapFile(const char* filename, const char* required_prefix);
 
   template <typename Line>
   bool FindById(uid_t uid, Line* line);
@@ -65,11 +65,12 @@
   const char* filename_ = nullptr;
   const char* start_ = nullptr;
   const char* end_ = nullptr;
+  const char* required_prefix_;
 };
 
 class PasswdFile {
  public:
-  PasswdFile(const char* filename);
+  PasswdFile(const char* filename, const char* required_prefix);
 
   bool FindById(uid_t id, passwd_state_t* passwd_state);
   bool FindByName(const char* name, passwd_state_t* passwd_state);
@@ -85,7 +86,7 @@
 
 class GroupFile {
  public:
-  GroupFile(const char* filename);
+  GroupFile(const char* filename, const char* required_prefix);
 
   bool FindById(gid_t id, group_state_t* group_state);
   bool FindByName(const char* name, group_state_t* group_state);