FirewallController.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. * Copyright (C) 2012 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. #include <set>
  17. #include <errno.h>
  18. #include <limits.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <cstdint>
  23. #define LOG_TAG "FirewallController"
  24. #define LOG_NDEBUG 0
  25. #include <android-base/file.h>
  26. #include <android-base/stringprintf.h>
  27. #include <android-base/strings.h>
  28. #include <log/log.h>
  29. #include "Controllers.h"
  30. #include "FirewallController.h"
  31. #include "NetdConstants.h"
  32. #include "bpf/BpfUtils.h"
  33. using android::base::Join;
  34. using android::base::ReadFileToString;
  35. using android::base::Split;
  36. using android::base::StringAppendF;
  37. using android::base::StringPrintf;
  38. using android::bpf::BpfLevel;
  39. using android::net::gCtls;
  40. namespace {
  41. // Default maximum valid uid in a normal root user namespace. The maximum valid uid is used in
  42. // rules that exclude all possible UIDs in the namespace in order to match packets that have
  43. // no socket associated with them.
  44. constexpr const uid_t kDefaultMaximumUid = UID_MAX - 1; // UID_MAX defined as UINT_MAX
  45. // Proc file containing the uid mapping for the user namespace of the current process.
  46. const char kUidMapProcFile[] = "/proc/self/uid_map";
  47. android::bpf::BpfLevel getBpfOwnerStatus() {
  48. return gCtls->trafficCtrl.getBpfLevel();
  49. }
  50. } // namespace
  51. namespace android {
  52. namespace net {
  53. auto FirewallController::execIptablesRestore = ::execIptablesRestore;
  54. const char* FirewallController::TABLE = "filter";
  55. const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
  56. const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
  57. const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
  58. const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
  59. const char* FirewallController::LOCAL_STANDBY = "fw_standby";
  60. const char* FirewallController::LOCAL_POWERSAVE = "fw_powersave";
  61. // ICMPv6 types that are required for any form of IPv6 connectivity to work. Note that because the
  62. // fw_dozable chain is called from both INPUT and OUTPUT, this includes both packets that we need
  63. // to be able to send (e.g., RS, NS), and packets that we need to receive (e.g., RA, NA).
  64. const char* FirewallController::ICMPV6_TYPES[] = {
  65. "packet-too-big",
  66. "router-solicitation",
  67. "router-advertisement",
  68. "neighbour-solicitation",
  69. "neighbour-advertisement",
  70. "redirect",
  71. };
  72. FirewallController::FirewallController(void) : mMaxUid(discoverMaximumValidUid(kUidMapProcFile)) {
  73. // If no rules are set, it's in BLACKLIST mode
  74. mFirewallType = BLACKLIST;
  75. mIfaceRules = {};
  76. }
  77. int FirewallController::setupIptablesHooks(void) {
  78. int res = 0;
  79. mUseBpfOwnerMatch = getBpfOwnerStatus();
  80. if (mUseBpfOwnerMatch != BpfLevel::NONE) {
  81. return res;
  82. }
  83. res |= createChain(LOCAL_DOZABLE, getFirewallType(DOZABLE));
  84. res |= createChain(LOCAL_STANDBY, getFirewallType(STANDBY));
  85. res |= createChain(LOCAL_POWERSAVE, getFirewallType(POWERSAVE));
  86. return res;
  87. }
  88. int FirewallController::setFirewallType(FirewallType ftype) {
  89. int res = 0;
  90. if (mFirewallType != ftype) {
  91. // flush any existing rules
  92. resetFirewall();
  93. if (ftype == WHITELIST) {
  94. // create default rule to drop all traffic
  95. std::string command =
  96. "*filter\n"
  97. "-A fw_INPUT -j DROP\n"
  98. "-A fw_OUTPUT -j REJECT\n"
  99. "-A fw_FORWARD -j REJECT\n"
  100. "COMMIT\n";
  101. res = execIptablesRestore(V4V6, command.c_str());
  102. }
  103. // Set this after calling disableFirewall(), since it defaults to WHITELIST there
  104. mFirewallType = ftype;
  105. }
  106. return res ? -EREMOTEIO : 0;
  107. }
  108. int FirewallController::resetFirewall(void) {
  109. mFirewallType = WHITELIST;
  110. mIfaceRules.clear();
  111. // flush any existing rules
  112. std::string command =
  113. "*filter\n"
  114. ":fw_INPUT -\n"
  115. ":fw_OUTPUT -\n"
  116. ":fw_FORWARD -\n"
  117. "COMMIT\n";
  118. return (execIptablesRestore(V4V6, command.c_str()) == 0) ? 0 : -EREMOTEIO;
  119. }
  120. int FirewallController::enableChildChains(ChildChain chain, bool enable) {
  121. int res = 0;
  122. const char* name;
  123. switch(chain) {
  124. case DOZABLE:
  125. name = LOCAL_DOZABLE;
  126. break;
  127. case STANDBY:
  128. name = LOCAL_STANDBY;
  129. break;
  130. case POWERSAVE:
  131. name = LOCAL_POWERSAVE;
  132. break;
  133. default:
  134. return res;
  135. }
  136. if (mUseBpfOwnerMatch != BpfLevel::NONE) {
  137. return gCtls->trafficCtrl.toggleUidOwnerMap(chain, enable);
  138. }
  139. std::string command = "*filter\n";
  140. for (const char *parent : { LOCAL_INPUT, LOCAL_OUTPUT }) {
  141. StringAppendF(&command, "%s %s -j %s\n", (enable ? "-A" : "-D"), parent, name);
  142. }
  143. StringAppendF(&command, "COMMIT\n");
  144. return execIptablesRestore(V4V6, command);
  145. }
  146. int FirewallController::isFirewallEnabled(void) {
  147. // TODO: verify that rules are still in place near top
  148. return -1;
  149. }
  150. int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
  151. if (mFirewallType == BLACKLIST) {
  152. // Unsupported in BLACKLIST mode
  153. return -EINVAL;
  154. }
  155. if (!isIfaceName(iface)) {
  156. errno = ENOENT;
  157. return -ENOENT;
  158. }
  159. // Only delete rules if we actually added them, because otherwise our iptables-restore
  160. // processes will terminate with "no such rule" errors and cause latency penalties while we
  161. // spin up new ones.
  162. const char* op;
  163. if (rule == ALLOW && mIfaceRules.find(iface) == mIfaceRules.end()) {
  164. op = "-I";
  165. mIfaceRules.insert(iface);
  166. } else if (rule == DENY && mIfaceRules.find(iface) != mIfaceRules.end()) {
  167. op = "-D";
  168. mIfaceRules.erase(iface);
  169. } else {
  170. return 0;
  171. }
  172. std::string command = Join(std::vector<std::string> {
  173. "*filter",
  174. StringPrintf("%s fw_INPUT -i %s -j RETURN", op, iface),
  175. StringPrintf("%s fw_OUTPUT -o %s -j RETURN", op, iface),
  176. "COMMIT\n"
  177. }, "\n");
  178. return (execIptablesRestore(V4V6, command) == 0) ? 0 : -EREMOTEIO;
  179. }
  180. FirewallType FirewallController::getFirewallType(ChildChain chain) {
  181. switch(chain) {
  182. case DOZABLE:
  183. return WHITELIST;
  184. case STANDBY:
  185. return BLACKLIST;
  186. case POWERSAVE:
  187. return WHITELIST;
  188. case NONE:
  189. return mFirewallType;
  190. default:
  191. return BLACKLIST;
  192. }
  193. }
  194. int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule) {
  195. const char* op;
  196. const char* target;
  197. FirewallType firewallType = getFirewallType(chain);
  198. if (firewallType == WHITELIST) {
  199. target = "RETURN";
  200. // When adding, insert RETURN rules at the front, before the catch-all DROP at the end.
  201. op = (rule == ALLOW)? "-I" : "-D";
  202. } else { // BLACKLIST mode
  203. target = "DROP";
  204. // When adding, append DROP rules at the end, after the RETURN rule that matches TCP RSTs.
  205. op = (rule == DENY)? "-A" : "-D";
  206. }
  207. std::vector<std::string> chainNames;
  208. switch(chain) {
  209. case DOZABLE:
  210. chainNames = { LOCAL_DOZABLE };
  211. break;
  212. case STANDBY:
  213. chainNames = { LOCAL_STANDBY };
  214. break;
  215. case POWERSAVE:
  216. chainNames = { LOCAL_POWERSAVE };
  217. break;
  218. case NONE:
  219. chainNames = { LOCAL_INPUT, LOCAL_OUTPUT };
  220. break;
  221. default:
  222. ALOGW("Unknown child chain: %d", chain);
  223. return -EINVAL;
  224. }
  225. if (mUseBpfOwnerMatch != BpfLevel::NONE) {
  226. return gCtls->trafficCtrl.changeUidOwnerRule(chain, uid, rule, firewallType);
  227. }
  228. std::string command = "*filter\n";
  229. for (const std::string& chainName : chainNames) {
  230. StringAppendF(&command, "%s %s -m owner --uid-owner %d -j %s\n",
  231. op, chainName.c_str(), uid, target);
  232. }
  233. StringAppendF(&command, "COMMIT\n");
  234. return (execIptablesRestore(V4V6, command) == 0) ? 0 : -EREMOTEIO;
  235. }
  236. int FirewallController::createChain(const char* chain, FirewallType type) {
  237. static const std::vector<int32_t> NO_UIDS;
  238. return replaceUidChain(chain, type == WHITELIST, NO_UIDS);
  239. }
  240. /* static */
  241. std::string FirewallController::makeCriticalCommands(IptablesTarget target, const char* chainName) {
  242. // Allow ICMPv6 packets necessary to make IPv6 connectivity work. http://b/23158230 .
  243. std::string commands;
  244. if (target == V6) {
  245. for (size_t i = 0; i < ARRAY_SIZE(ICMPV6_TYPES); i++) {
  246. StringAppendF(&commands, "-A %s -p icmpv6 --icmpv6-type %s -j RETURN\n",
  247. chainName, ICMPV6_TYPES[i]);
  248. }
  249. }
  250. return commands;
  251. }
  252. std::string FirewallController::makeUidRules(IptablesTarget target, const char *name,
  253. bool isWhitelist, const std::vector<int32_t>& uids) {
  254. std::string commands;
  255. StringAppendF(&commands, "*filter\n:%s -\n", name);
  256. // Whitelist chains have UIDs at the beginning, and new UIDs are added with '-I'.
  257. if (isWhitelist) {
  258. for (auto uid : uids) {
  259. StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j RETURN\n", name, uid);
  260. }
  261. // Always whitelist system UIDs.
  262. StringAppendF(&commands,
  263. "-A %s -m owner --uid-owner %d-%d -j RETURN\n", name, 0, MAX_SYSTEM_UID);
  264. // This rule inverts the match for all UIDs; ie, if there is no UID match here,
  265. // there is no socket to be found
  266. StringAppendF(&commands,
  267. "-A %s -m owner ! --uid-owner %d-%u -j RETURN\n", name, 0, mMaxUid);
  268. // Always whitelist traffic with protocol ESP, or no known socket - required for IPSec
  269. StringAppendF(&commands, "-A %s -p esp -j RETURN\n", name);
  270. }
  271. // Always allow networking on loopback.
  272. StringAppendF(&commands, "-A %s -i lo -j RETURN\n", name);
  273. StringAppendF(&commands, "-A %s -o lo -j RETURN\n", name);
  274. // Allow TCP RSTs so we can cleanly close TCP connections of apps that no longer have network
  275. // access. Both incoming and outgoing RSTs are allowed.
  276. StringAppendF(&commands, "-A %s -p tcp --tcp-flags RST RST -j RETURN\n", name);
  277. if (isWhitelist) {
  278. commands.append(makeCriticalCommands(target, name));
  279. }
  280. // Blacklist chains have UIDs at the end, and new UIDs are added with '-A'.
  281. if (!isWhitelist) {
  282. for (auto uid : uids) {
  283. StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j DROP\n", name, uid);
  284. }
  285. }
  286. // If it's a whitelist chain, add a default DROP at the end. This is not necessary for a
  287. // blacklist chain, because all user-defined chains implicitly RETURN at the end.
  288. if (isWhitelist) {
  289. StringAppendF(&commands, "-A %s -j DROP\n", name);
  290. }
  291. StringAppendF(&commands, "COMMIT\n");
  292. return commands;
  293. }
  294. int FirewallController::replaceUidChain(
  295. const std::string &name, bool isWhitelist, const std::vector<int32_t>& uids) {
  296. if (mUseBpfOwnerMatch != BpfLevel::NONE) {
  297. return gCtls->trafficCtrl.replaceUidOwnerMap(name, isWhitelist, uids);
  298. }
  299. std::string commands4 = makeUidRules(V4, name.c_str(), isWhitelist, uids);
  300. std::string commands6 = makeUidRules(V6, name.c_str(), isWhitelist, uids);
  301. return execIptablesRestore(V4, commands4.c_str()) | execIptablesRestore(V6, commands6.c_str());
  302. }
  303. /* static */
  304. uid_t FirewallController::discoverMaximumValidUid(const std::string& fileName) {
  305. std::string content;
  306. if (!ReadFileToString(fileName, &content, false)) {
  307. // /proc/self/uid_map only exists if a uid mapping has been set.
  308. ALOGD("Could not read %s, max uid defaulting to %u", fileName.c_str(), kDefaultMaximumUid);
  309. return kDefaultMaximumUid;
  310. }
  311. std::vector<std::string> lines = Split(content, "\n");
  312. if (lines.empty()) {
  313. ALOGD("%s was empty, max uid defaulting to %u", fileName.c_str(), kDefaultMaximumUid);
  314. return kDefaultMaximumUid;
  315. }
  316. uint32_t maxUid = 0;
  317. for (const auto& line : lines) {
  318. if (line.empty()) {
  319. continue;
  320. }
  321. // Choose the end of the largest range found in the file.
  322. uint32_t start;
  323. uint32_t ignored;
  324. uint32_t rangeLength;
  325. int items = sscanf(line.c_str(), "%u %u %u", &start, &ignored, &rangeLength);
  326. if (items != 3) {
  327. // uid_map lines must have 3 items, see the man page of 'user_namespaces' for details.
  328. ALOGD("Format of %s unrecognized, max uid defaulting to %u", fileName.c_str(),
  329. kDefaultMaximumUid);
  330. return kDefaultMaximumUid;
  331. }
  332. maxUid = std::max(maxUid, start + rangeLength - 1);
  333. }
  334. if (maxUid == 0) {
  335. ALOGD("No max uid found, max uid defaulting to %u", kDefaultMaximumUid);
  336. return kDefaultMaximumUid;
  337. }
  338. return maxUid;
  339. }
  340. } // namespace net
  341. } // namespace android