OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // The following is duplicated from base/linux_utils.cc. |
| 6 // We shouldn't link against C++ code in a setuid binary. |
| 7 |
| 8 #include "linux_util.h" |
| 9 |
| 10 #include <dirent.h> |
| 11 #include <limits.h> |
| 12 #include <stdio.h> |
| 13 #include <stdlib.h> |
| 14 #include <string.h> |
| 15 #include <sys/stat.h> |
| 16 #include <sys/types.h> |
| 17 #include <unistd.h> |
| 18 |
| 19 // expected prefix of the target of the /proc/self/fd/%d link for a socket |
| 20 static const char kSocketLinkPrefix[] = "socket:["; |
| 21 |
| 22 // Parse a symlink in /proc/pid/fd/$x and return the inode number of the |
| 23 // socket. |
| 24 // inode_out: (output) set to the inode number on success |
| 25 // path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor) |
| 26 static bool ProcPathGetInode(ino_t* inode_out, const char* path) { |
| 27 char buf[256]; |
| 28 const ssize_t n = readlink(path, buf, sizeof(buf) - 1); |
| 29 if (n == -1) |
| 30 return false; |
| 31 buf[n] = 0; |
| 32 |
| 33 if (memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) |
| 34 return false; |
| 35 |
| 36 char *endptr; |
| 37 const unsigned long long int inode_ul = |
| 38 strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10); |
| 39 if (*endptr != ']') |
| 40 return false; |
| 41 |
| 42 if (inode_ul == ULLONG_MAX) |
| 43 return false; |
| 44 |
| 45 *inode_out = inode_ul; |
| 46 return true; |
| 47 } |
| 48 |
| 49 bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode) { |
| 50 bool already_found = false; |
| 51 |
| 52 DIR* proc = opendir("/proc"); |
| 53 if (!proc) |
| 54 return false; |
| 55 |
| 56 const uid_t uid = getuid(); |
| 57 struct dirent* dent; |
| 58 while ((dent = readdir(proc))) { |
| 59 char *endptr; |
| 60 const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10); |
| 61 if (pid_ul == ULONG_MAX || *endptr) |
| 62 continue; |
| 63 |
| 64 // We have this setuid code here because the zygote and its children have |
| 65 // /proc/$pid/fd owned by root. While scanning through /proc, we add this |
| 66 // extra check so users cannot accidentally gain information about other |
| 67 // users' processes. To determine process ownership, we use the property |
| 68 // that if user foo owns process N, then /proc/N is owned by foo. |
| 69 { |
| 70 char buf[256]; |
| 71 struct stat statbuf; |
| 72 snprintf(buf, sizeof(buf), "/proc/%lu", pid_ul); |
| 73 if (stat(buf, &statbuf) < 0) |
| 74 continue; |
| 75 if (uid != statbuf.st_uid) |
| 76 continue; |
| 77 } |
| 78 |
| 79 char buf[256]; |
| 80 snprintf(buf, sizeof(buf), "/proc/%lu/fd", pid_ul); |
| 81 DIR* fd = opendir(buf); |
| 82 if (!fd) |
| 83 continue; |
| 84 |
| 85 while ((dent = readdir(fd))) { |
| 86 if (snprintf(buf, sizeof(buf), "/proc/%lu/fd/%s", pid_ul, |
| 87 dent->d_name) >= sizeof(buf) - 1) { |
| 88 continue; |
| 89 } |
| 90 |
| 91 ino_t fd_inode; |
| 92 if (ProcPathGetInode(&fd_inode, buf)) { |
| 93 if (fd_inode == socket_inode) { |
| 94 if (already_found) { |
| 95 closedir(fd); |
| 96 closedir(proc); |
| 97 return false; |
| 98 } |
| 99 |
| 100 already_found = true; |
| 101 *pid_out = pid_ul; |
| 102 break; |
| 103 } |
| 104 } |
| 105 } |
| 106 closedir(fd); |
| 107 } |
| 108 closedir(proc); |
| 109 |
| 110 return already_found; |
| 111 } |
OLD | NEW |