+// Run do_search_file() in a child process.
+//
+// The reason for this is that we're not robust against malicious input, so we need
+// to drop privileges after opening the file. (Otherwise, we could fall prey to an attack
+// where a user does locate -d badfile.db:/var/lib/plocate/plocate.db, badfile.db contains
+// a buffer overflow that takes over the process, and then uses the elevated privileges
+// to print out otherwise inaccessible paths.) We solve this by forking and treating the
+// child process as untrusted after it has dropped its privileges (which it does before
+// reading any data from the file); it returns a single 64-bit number over a pipe,
+// and that's it. The parent keeps its privileges, and can then fork out new children
+// without fear of being taken over. (The child keeps stdout for outputting results.)
+//
+// The count is returned over the pipe, because it's needed both for --limit and --count.
+uint64_t do_search_file_in_child(const vector<Needle> &needles, const std::string &filename)
+{
+ int pipefd[2];
+ if (pipe(pipefd) == -1) {
+ perror("pipe");
+ exit(EXIT_FAILURE);
+ }
+
+ pid_t child_pid = fork();
+ switch (child_pid) {
+ case 0: {
+ // Child.
+ close(pipefd[0]);
+ in_forked_child = true;
+ uint64_t matched = do_search_file(needles, filename);
+ int ret;
+ do {
+ ret = write(pipefd[1], &matched, sizeof(matched));
+ } while (ret == -1 && errno == EINTR);
+ if (ret != sizeof(matched)) {
+ perror("write");
+ _exit(EXIT_FAILURE);
+ }
+ fflush(stdout);
+ _exit(EXIT_SUCCESS);