Empty merge of sc-v2-dev-plus-aosp-without-vendor@8084891

Bug: 214455710
Merged-In: I012cfb9b01e5d21ec71700c3c52ac9c096cd1a90
Change-Id: I67f80ee94d0f1f273ef49aa45ea0e4674311892b
diff --git a/Utils.cpp b/Utils.cpp
index f059c67..864cbf8 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -754,7 +754,53 @@
     return OK;
 }
 
-pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
+status_t ForkExecvpTimeout(const std::vector<std::string>& args, std::chrono::seconds timeout,
+                           char* context) {
+    int status;
+
+    pid_t wait_timeout_pid = fork();
+    if (wait_timeout_pid == 0) {
+        pid_t pid = ForkExecvpAsync(args, context);
+        if (pid == -1) {
+            _exit(EXIT_FAILURE);
+        }
+        pid_t timer_pid = fork();
+        if (timer_pid == 0) {
+            sleep(timeout.count());
+            _exit(ETIMEDOUT);
+        }
+        if (timer_pid == -1) {
+            PLOG(ERROR) << "fork in ForkExecvpAsync_timeout";
+            kill(pid, SIGTERM);
+            _exit(EXIT_FAILURE);
+        }
+        pid_t finished = wait(&status);
+        if (finished == pid) {
+            kill(timer_pid, SIGTERM);
+        } else {
+            kill(pid, SIGTERM);
+        }
+        if (!WIFEXITED(status)) {
+            _exit(ECHILD);
+        }
+        _exit(WEXITSTATUS(status));
+    }
+    if (waitpid(wait_timeout_pid, &status, 0) == -1) {
+        PLOG(ERROR) << "waitpid in ForkExecvpAsync_timeout";
+        return -errno;
+    }
+    if (!WIFEXITED(status)) {
+        LOG(ERROR) << "Process did not exit normally, status: " << status;
+        return -ECHILD;
+    }
+    if (WEXITSTATUS(status)) {
+        LOG(ERROR) << "Process exited with code: " << WEXITSTATUS(status);
+        return WEXITSTATUS(status);
+    }
+    return OK;
+}
+
+pid_t ForkExecvpAsync(const std::vector<std::string>& args, char* context) {
     auto argv = ConvertToArgv(args);
 
     pid_t pid = fork();
@@ -762,6 +808,12 @@
         close(STDIN_FILENO);
         close(STDOUT_FILENO);
         close(STDERR_FILENO);
+        if (context) {
+            if (setexeccon(context)) {
+                LOG(ERROR) << "Failed to setexeccon in ForkExecvpAsync";
+                abort();
+            }
+        }
 
         execvp(argv[0], const_cast<char**>(argv.data()));
         PLOG(ERROR) << "exec in ForkExecvpAsync";
@@ -1442,6 +1494,17 @@
     namespace fs = std::filesystem;
 
     for (const auto& itEntry : fs::directory_iterator("/sys/fs/fuse/connections")) {
+        std::string fsPath = itEntry.path().string() + "/filesystem";
+        std::string fs;
+
+        // Virtiofs is on top of fuse and there isn't any user space daemon.
+        // Android user space doesn't manage it.
+        if (android::base::ReadFileToString(fsPath, &fs, false) &&
+            android::base::Trim(fs) == "virtiofs") {
+            LOG(INFO) << "Ignore virtiofs connection entry " << itEntry.path().string();
+            continue;
+        }
+
         std::string abortPath = itEntry.path().string() + "/abort";
         LOG(DEBUG) << "Aborting fuse connection entry " << abortPath;
         bool ret = writeStringToFile("1", abortPath);
diff --git a/Utils.h b/Utils.h
index 3585e53..2d54639 100644
--- a/Utils.h
+++ b/Utils.h
@@ -39,6 +39,8 @@
 static const char* kExternalStorageSdcardfs = "external_storage.sdcardfs.enabled";
 static const char* kFuseBpfEnabled = "persist.sys.fuse.bpf.enable";
 
+static constexpr std::chrono::seconds kUntrustedFsckSleepTime(45);
+
 /* SELinux contexts used depending on the block device type */
 extern char* sBlkidContext;
 extern char* sBlkidUntrustedContext;
@@ -108,8 +110,10 @@
 /* Returns either WEXITSTATUS() status, or a negative errno */
 status_t ForkExecvp(const std::vector<std::string>& args,
                     std::vector<std::string>* output = nullptr, char* context = nullptr);
+status_t ForkExecvpTimeout(const std::vector<std::string>& args, std::chrono::seconds timeout,
+                           char* context = nullptr);
 
-pid_t ForkExecvpAsync(const std::vector<std::string>& args);
+pid_t ForkExecvpAsync(const std::vector<std::string>& args, char* context = nullptr);
 
 /* Gets block device size in bytes */
 status_t GetBlockDevSize(int fd, uint64_t* size);
diff --git a/fs/Exfat.cpp b/fs/Exfat.cpp
index 7782dd3..c8b19e0 100644
--- a/fs/Exfat.cpp
+++ b/fs/Exfat.cpp
@@ -44,7 +44,7 @@
     cmd.push_back("-y");
     cmd.push_back(source);
 
-    int rc = ForkExecvp(cmd, nullptr, sFsckUntrustedContext);
+    int rc = ForkExecvpTimeout(cmd, kUntrustedFsckSleepTime, sFsckUntrustedContext);
     if (rc == 0) {
         LOG(INFO) << "Check OK";
         return 0;
diff --git a/fs/Vfat.cpp b/fs/Vfat.cpp
index 4f1e982..f3f04d8 100644
--- a/fs/Vfat.cpp
+++ b/fs/Vfat.cpp
@@ -68,10 +68,9 @@
         cmd.push_back(source);
 
         // Fat devices are currently always untrusted
-        rc = ForkExecvp(cmd, nullptr, sFsckUntrustedContext);
-
+        rc = ForkExecvpTimeout(cmd, kUntrustedFsckSleepTime, sFsckUntrustedContext);
         if (rc < 0) {
-            LOG(ERROR) << "Filesystem check failed due to logwrap error";
+            LOG(ERROR) << "Filesystem check failed due to fork error";
             errno = EIO;
             return -1;
         }
@@ -81,6 +80,10 @@
                 LOG(INFO) << "Filesystem check completed OK";
                 return 0;
 
+            case 1:
+                LOG(INFO) << "Failed to check filesystem";
+                return -1;
+
             case 2:
                 LOG(ERROR) << "Filesystem check failed (not a FAT filesystem)";
                 errno = ENODATA;
@@ -100,6 +103,11 @@
                 errno = ENODATA;
                 return -1;
 
+            case ETIMEDOUT:
+                LOG(ERROR) << "Filesystem check timed out";
+                errno = ETIMEDOUT;
+                return -1;
+
             default:
                 LOG(ERROR) << "Filesystem check failed (unknown exit code " << rc << ")";
                 errno = EIO;