• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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/commands/cvd/selector/selector_constants.h"
18 
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 #include <deque>
23 #include <sstream>
24 
25 #include "common/libs/fs/shared_buf.h"
26 #include "common/libs/fs/shared_fd.h"
27 #include "common/libs/utils/environment.h"
28 #include "common/libs/utils/files.h"
29 #include "common/libs/utils/users.h"
30 
31 namespace cuttlefish {
32 namespace selector {
33 
34 enum class OwnershipType { kUser, kGroup, kOthers };
35 
GetOwnershipType(const struct stat & file_stat,const uid_t uid,const gid_t gid)36 static OwnershipType GetOwnershipType(const struct stat& file_stat,
37                                       const uid_t uid, const gid_t gid) {
38   if (file_stat.st_uid == uid) {
39     return OwnershipType::kUser;
40   }
41   if (file_stat.st_gid == gid) {
42     return OwnershipType::kGroup;
43   }
44   return OwnershipType::kOthers;
45 }
46 
47 struct RequirePermission {
48   const bool needs_read_permission;
49   const bool needs_write_permission;
50   const bool needs_exec_permission;
51 };
52 
CheckPermission(const OwnershipType ownership_type,const struct stat & file_stat,const RequirePermission & perm)53 static Result<void> CheckPermission(const OwnershipType ownership_type,
54                                     const struct stat& file_stat,
55                                     const RequirePermission& perm) {
56   const auto perm_bits = file_stat.st_mode;
57 
58   switch (ownership_type) {
59     case OwnershipType::kUser: {
60       CF_EXPECT(!perm.needs_read_permission || (perm_bits & S_IRUSR));
61       CF_EXPECT(!perm.needs_write_permission || (perm_bits & S_IWUSR));
62       CF_EXPECT(!perm.needs_exec_permission || (perm_bits & S_IXUSR));
63       return {};
64     }
65     case OwnershipType::kGroup: {
66       CF_EXPECT(!perm.needs_read_permission || (perm_bits & S_IRGRP));
67       CF_EXPECT(!perm.needs_write_permission || (perm_bits & S_IWGRP));
68       CF_EXPECT(!perm.needs_exec_permission || (perm_bits & S_IXGRP));
69       return {};
70     }
71     case OwnershipType::kOthers:
72       break;
73   }
74   CF_EXPECT(!perm.needs_read_permission || (perm_bits & S_IROTH));
75   CF_EXPECT(!perm.needs_write_permission || (perm_bits & S_IWOTH));
76   CF_EXPECT(!perm.needs_exec_permission || (perm_bits & S_IXOTH));
77   return {};
78 }
79 
CheckPermission(const std::string & dir,const uid_t client_uid,const gid_t client_gid)80 static Result<void> CheckPermission(const std::string& dir,
81                                     const uid_t client_uid,
82                                     const gid_t client_gid) {
83   CF_EXPECT(!dir.empty() && DirectoryExists(dir));
84   struct stat dir_stat;
85   CF_EXPECT_EQ(stat(dir.c_str(), std::addressof(dir_stat)), 0);
86 
87   const auto server_ownership = GetOwnershipType(dir_stat, getuid(), getgid());
88   CF_EXPECT(CheckPermission(server_ownership, dir_stat,
89                             RequirePermission{.needs_read_permission = true,
90                                               .needs_write_permission = true,
91                                               .needs_exec_permission = true}));
92   const auto client_ownership =
93       GetOwnershipType(dir_stat, client_uid, client_gid);
94   CF_EXPECT(CheckPermission(client_ownership, dir_stat,
95                             RequirePermission{.needs_read_permission = true,
96                                               .needs_write_permission = true,
97                                               .needs_exec_permission = true}));
98   return {};
99 }
100 
ParentOfAutogeneratedHomes(const uid_t client_uid,const gid_t client_gid)101 Result<std::string> ParentOfAutogeneratedHomes(const uid_t client_uid,
102                                                const gid_t client_gid) {
103   std::deque<std::string> try_dirs = {
104       StringFromEnv("TMPDIR", ""),
105       StringFromEnv("TEMP", ""),
106       StringFromEnv("TMP", ""),
107       "/tmp",
108       "/var/tmp",
109       "/usr/tmp",
110   };
111 
112   auto system_wide_home = SystemWideUserHome(client_uid);
113   if (system_wide_home.ok()) {
114     try_dirs.emplace_back(*system_wide_home);
115   }
116   try_dirs.emplace_back(AbsolutePath("."));
117   while (!try_dirs.empty()) {
118     const auto candidate = std::move(try_dirs.front());
119     try_dirs.pop_front();
120     if (candidate.empty() || !EnsureDirectoryExists(candidate).ok()) {
121       continue;
122     }
123     CF_EXPECT(CheckPermission(candidate, client_uid, client_gid));
124     return AbsolutePath(candidate);
125   }
126   return CF_ERR("Tried all candidate directories but none was read-writable.");
127 }
128 
GroupNameFlag(const std::string & name)129 CvdFlag<std::string> SelectorFlags::GroupNameFlag(const std::string& name) {
130   CvdFlag<std::string> group_name{name};
131   std::stringstream group_name_help;
132   group_name_help << "--" << name << "=<"
133                   << "name of the instance group>";
134   group_name.SetHelpMessage(group_name_help.str());
135   return group_name;
136 }
137 
InstanceNameFlag(const std::string & name)138 CvdFlag<std::string> SelectorFlags::InstanceNameFlag(const std::string& name) {
139   CvdFlag<std::string> instance_name{name};
140   std::stringstream instance_name_help;
141   instance_name_help << "--" << name << "=<"
142                      << "comma-separated names of the instances>";
143   instance_name.SetHelpMessage(instance_name_help.str());
144   return instance_name;
145 }
146 
DisableDefaultGroupFlag(const std::string & name,const bool default_val)147 CvdFlag<bool> SelectorFlags::DisableDefaultGroupFlag(const std::string& name,
148                                                      const bool default_val) {
149   CvdFlag<bool> disable_default_group(name, default_val);
150   std::stringstream help;
151   help << "--" << name << "=true not to create the default instance group.";
152   disable_default_group.SetHelpMessage(help.str());
153   return disable_default_group;
154 }
155 
AcquireFileLockFlag(const std::string & name,const bool default_val)156 CvdFlag<bool> SelectorFlags::AcquireFileLockFlag(const std::string& name,
157                                                  const bool default_val) {
158   CvdFlag<bool> acquire_file_lock(name, default_val);
159   std::stringstream help;
160   help << "--" << name
161        << "=false for cvd server not to acquire lock file locks.";
162   acquire_file_lock.SetHelpMessage(help.str());
163   return acquire_file_lock;
164 }
165 
Get()166 const SelectorFlags& SelectorFlags::Get() {
167   static SelectorFlags singleton_selector_flags;
168   return singleton_selector_flags;
169 }
170 
New()171 const SelectorFlags SelectorFlags::New() {
172   SelectorFlags selector_flags;
173   return selector_flags;
174 }
175 
176 }  // namespace selector
177 }  // namespace cuttlefish
178