1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/vm_manager/vhost_user.h"
18 
19 #include <sys/socket.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/un.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 
26 #include <cstdlib>
27 #include <string>
28 #include <utility>
29 
30 #include <android-base/logging.h>
31 #include <android-base/strings.h>
32 #include <vulkan/vulkan.h>
33 
34 #include "common/libs/utils/files.h"
35 #include "common/libs/utils/result.h"
36 #include "common/libs/utils/subprocess.h"
37 #include "host/libs/config/cuttlefish_config.h"
38 #include "host/libs/vm_manager/crosvm_builder.h"
39 
40 namespace cuttlefish {
41 namespace vm_manager {
42 
43 // TODO(schuffelen): Deduplicate with BuildVhostUserGpu
VhostUserBlockDevice(const CuttlefishConfig & config,int num,std::string_view disk_path)44 Result<VhostUserDeviceCommands> VhostUserBlockDevice(
45     const CuttlefishConfig& config, int num, std::string_view disk_path) {
46   const auto& instance = config.ForDefaultInstance();
47 
48   CF_EXPECT(instance.vhost_user_block(), "Feature is not enabled");
49 
50   auto block_device_socket_path = instance.PerInstanceInternalUdsPath(
51       fmt::format("vhost-user-block-{}-socket", num));
52   auto block_device_logs_path = instance.PerInstanceInternalPath(
53       fmt::format("crosvm_vhost_user_block_{}.fifo", num));
54   auto block_device_logs =
55       CF_EXPECT(SharedFD::Fifo(block_device_logs_path, 0666));
56 
57   Command block_device_logs_cmd(HostBinaryPath("log_tee"));
58   block_device_logs_cmd.AddParameter("--process_name=crosvm_block_", num);
59   block_device_logs_cmd.AddParameter("--log_fd_in=", block_device_logs);
60   block_device_logs_cmd.SetStopper(KillSubprocessFallback([](Subprocess* proc) {
61     // Ask nicely so that log_tee gets a chance to process all the logs.
62     // TODO: b/335934714 - Make sure the process actually exits
63     bool res = kill(proc->pid(), SIGINT) == 0;
64     return res ? StopperResult::kStopSuccess : StopperResult::kStopFailure;
65   }));
66 
67   const std::string crosvm_path = config.crosvm_binary();
68 
69   CrosvmBuilder block_device_cmd;
70 
71   // NOTE: The "main" crosvm process returns a kCrosvmVmResetExitCode when the
72   // guest exits but the "block" crosvm just exits cleanly with 0 after the
73   // "main" crosvm disconnects.
74   block_device_cmd.ApplyProcessRestarter(config.crosvm_binary(),
75                                          /*first_time_argument=*/"",
76                                          /*exit_code=*/0);
77 
78   block_device_cmd.Cmd().AddParameter("devices");
79   block_device_cmd.Cmd().AddParameter("--block");
80   block_device_cmd.Cmd().AddParameter("vhost=", block_device_socket_path,
81                                       ",path=", disk_path);
82 
83   if (instance.enable_sandbox()) {
84     const bool seccomp_exists = DirectoryExists(instance.seccomp_policy_dir());
85     const std::string& var_empty_dir = kCrosvmVarEmptyDir;
86     const bool var_empty_available = DirectoryExists(var_empty_dir);
87     CF_EXPECT(var_empty_available && seccomp_exists,
88               var_empty_dir << " is not an existing, empty directory."
89                             << "seccomp-policy-dir, "
90                             << instance.seccomp_policy_dir()
91                             << " does not exist");
92     block_device_cmd.Cmd().AddParameter("--jail");
93     block_device_cmd.Cmd().AddParameter("seccomp-policy-dir=",
94                                         instance.seccomp_policy_dir());
95   } else {
96     block_device_cmd.Cmd().AddParameter("--disable-sandbox");
97   }
98 
99   return (VhostUserDeviceCommands){
100       .device_cmd = std::move(block_device_cmd.Cmd()),
101       .device_logs_cmd = std::move(block_device_logs_cmd),
102       .socket_path = block_device_socket_path,
103   };
104 }
105 
106 }  // namespace vm_manager
107 }  // namespace cuttlefish
108