5252# include <elf.h>
5353# include <fcntl.h>
5454# include <link.h> // For ElfW() macro.
55+ # include <sys/resource.h>
5556# include <sys/stat.h>
5657# include <sys/types.h>
5758# include <unistd.h>
@@ -376,6 +377,40 @@ class Symbolizer {
376377 SymbolCacheLine symbol_cache_[SYMBOL_CACHE_LINES];
377378};
378379
380+ // Protect against client code closing low-valued file descriptors it doesn't
381+ // actually own, as has happened in b/384213477.
382+ int SaferOpen (const char * fname, int flags) {
383+ static int high_fd = [] {
384+ struct rlimit rlim{};
385+ const int rc = getrlimit (RLIMIT_NOFILE, & rlim);
386+ if (rc == 0 && rlim.rlim_cur >= 2000 ) {
387+ const int max_fd = static_cast< int> (rlim.rlim_cur);
388+
389+ // This will return 2000 on reasonably-configured systems.
390+ return std ::min< int> (2000 , max_fd - 1000 );
391+ }
392+ ABSL_RAW_LOG (WARNING, " Unable to get high fd: rc=%d, limit=%ld" , //
393+ rc, static_cast< long> (rlim.rlim_cur));
394+ return - 1 ;
395+ }();
396+ if (high_fd >= 1000 ) {
397+ const int fd = open (fname, flags);
398+ if (fd ! = - 1 && fd < high_fd) {
399+ // Try to relocate fd to high range.
400+ const int fd2 = fcntl (fd, F_DUPFD, high_fd);
401+ if (fd2 ! = - 1 ) {
402+ // Successfully obtained high fd. Use it.
403+ close (fd);
404+ return fd2;
405+ }
406+ }
407+ // Either open failed and fd==-1, or fd is already above high_fd, or fcntl
408+ // failed and fd is valid (but low).
409+ return fd;
410+ }
411+ return open (fname, flags);
412+ }
413+
379414static std ::atomic< Symbolizer * > g_cached_symbolizer;
380415
381416} // namespace
@@ -1064,7 +1099,7 @@ static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap(
10641099 snprintf (maps_path, sizeof (maps_path), " /proc/self/task/%d/maps" , getpid ());
10651100
10661101 int maps_fd;
1067- NO_INTR (maps_fd = open (maps_path, O_RDONLY));
1102+ NO_INTR (maps_fd = SaferOpen (maps_path, O_RDONLY));
10681103 FileDescriptor wrapped_maps_fd (maps_fd);
10691104 if (wrapped_maps_fd.get () < 0 ) {
10701105 ABSL_RAW_LOG (WARNING, " %s: errno=%d" , maps_path, errno);
@@ -1338,7 +1373,7 @@ static void MaybeOpenFdFromSelfExe(ObjFile *obj) {
13381373 if (memcmp (obj- > start_addr, ELFMAG, SELFMAG) ! = 0 ) {
13391374 return ;
13401375 }
1341- int fd = open (" /proc/self/exe" , O_RDONLY);
1376+ int fd = SaferOpen (" /proc/self/exe" , O_RDONLY);
13421377 if (fd == - 1 ) {
13431378 return ;
13441379 }
@@ -1362,15 +1397,15 @@ static void MaybeOpenFdFromSelfExe(ObjFile *obj) {
13621397
13631398static bool MaybeInitializeObjFile (ObjFile * obj) {
13641399 if (obj- > fd < 0 ) {
1365- obj- > fd = open (obj- > filename, O_RDONLY);
1400+ obj- > fd = SaferOpen (obj- > filename, O_RDONLY);
13661401
13671402 if (obj- > fd < 0 ) {
13681403 // Getting /proc/self/exe here means that we were hinted.
13691404 if (strcmp (obj- > filename, " /proc/self/exe" ) == 0 ) {
13701405 // /proc/self/exe may be inaccessible (due to setuid, etc.), so try
13711406 // accessing the binary via argv0.
13721407 if (argv0_value ! = nullptr) {
1373- obj- > fd = open (argv0_value, O_RDONLY);
1408+ obj- > fd = SaferOpen (argv0_value, O_RDONLY);
13741409 }
13751410 } else {
13761411 MaybeOpenFdFromSelfExe (obj);
0 commit comments