• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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  * FirewallControllerTest.cpp - unit tests for FirewallController.cpp
17  */
18 
19 #include <string>
20 #include <vector>
21 #include <stdio.h>
22 
23 #include <gtest/gtest.h>
24 
25 #include <android-base/file.h>
26 #include <android-base/stringprintf.h>
27 #include <android-base/strings.h>
28 
29 #include "FirewallController.h"
30 #include "IptablesBaseTest.h"
31 
32 using android::base::Join;
33 using android::base::WriteStringToFile;
34 
35 namespace android {
36 namespace net {
37 
38 class FirewallControllerTest : public IptablesBaseTest {
39 protected:
FirewallControllerTest()40     FirewallControllerTest() {
41         FirewallController::execIptablesRestore = fakeExecIptablesRestore;
42         // This unit test currently doesn't cover the eBPF owner match case so
43         // we have to manually turn eBPF support off.
44         // TODO: find a way to unit test the eBPF code path.
45         mFw.mUseBpfOwnerMatch = android::bpf::BpfLevel::NONE;
46     }
47     FirewallController mFw;
48 
makeUidRules(IptablesTarget a,const char * b,bool c,const std::vector<int32_t> & d)49     std::string makeUidRules(IptablesTarget a, const char* b, bool c,
50                              const std::vector<int32_t>& d) {
51         return mFw.makeUidRules(a, b, c, d);
52     }
53 
createChain(const char * a,FirewallType b)54     int createChain(const char* a, FirewallType b) {
55         return mFw.createChain(a, b);
56     }
57 };
58 
TEST_F(FirewallControllerTest,TestCreateWhitelistChain)59 TEST_F(FirewallControllerTest, TestCreateWhitelistChain) {
60     std::vector<std::string> expectedRestore4 = {
61         "*filter",
62         ":fw_whitelist -",
63         "-A fw_whitelist -m owner --uid-owner 0-9999 -j RETURN",
64         "-A fw_whitelist -m owner ! --uid-owner 0-4294967294 -j RETURN",
65         "-A fw_whitelist -p esp -j RETURN",
66         "-A fw_whitelist -i lo -j RETURN",
67         "-A fw_whitelist -o lo -j RETURN",
68         "-A fw_whitelist -p tcp --tcp-flags RST RST -j RETURN",
69         "-A fw_whitelist -j DROP",
70         "COMMIT\n"
71     };
72     std::vector<std::string> expectedRestore6 = {
73         "*filter",
74         ":fw_whitelist -",
75         "-A fw_whitelist -m owner --uid-owner 0-9999 -j RETURN",
76         "-A fw_whitelist -m owner ! --uid-owner 0-4294967294 -j RETURN",
77         "-A fw_whitelist -p esp -j RETURN",
78         "-A fw_whitelist -i lo -j RETURN",
79         "-A fw_whitelist -o lo -j RETURN",
80         "-A fw_whitelist -p tcp --tcp-flags RST RST -j RETURN",
81         "-A fw_whitelist -p icmpv6 --icmpv6-type packet-too-big -j RETURN",
82         "-A fw_whitelist -p icmpv6 --icmpv6-type router-solicitation -j RETURN",
83         "-A fw_whitelist -p icmpv6 --icmpv6-type router-advertisement -j RETURN",
84         "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN",
85         "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN",
86         "-A fw_whitelist -p icmpv6 --icmpv6-type redirect -j RETURN",
87         "-A fw_whitelist -j DROP",
88         "COMMIT\n"
89     };
90     std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
91             {V4, Join(expectedRestore4, '\n')},
92             {V6, Join(expectedRestore6, '\n')},
93     };
94 
95     createChain("fw_whitelist", WHITELIST);
96     expectIptablesRestoreCommands(expectedRestoreCommands);
97 }
98 
TEST_F(FirewallControllerTest,TestCreateBlacklistChain)99 TEST_F(FirewallControllerTest, TestCreateBlacklistChain) {
100     std::vector<std::string> expectedRestore = {
101         "*filter",
102         ":fw_blacklist -",
103         "-A fw_blacklist -i lo -j RETURN",
104         "-A fw_blacklist -o lo -j RETURN",
105         "-A fw_blacklist -p tcp --tcp-flags RST RST -j RETURN",
106         "COMMIT\n"
107     };
108     std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
109             {V4, Join(expectedRestore, '\n')},
110             {V6, Join(expectedRestore, '\n')},
111     };
112 
113     createChain("fw_blacklist", BLACKLIST);
114     expectIptablesRestoreCommands(expectedRestoreCommands);
115 }
116 
TEST_F(FirewallControllerTest,TestSetStandbyRule)117 TEST_F(FirewallControllerTest, TestSetStandbyRule) {
118     ExpectedIptablesCommands expected = {
119         { V4V6, "*filter\n-D fw_standby -m owner --uid-owner 12345 -j DROP\nCOMMIT\n" }
120     };
121     mFw.setUidRule(STANDBY, 12345, ALLOW);
122     expectIptablesRestoreCommands(expected);
123 
124     expected = {
125         { V4V6, "*filter\n-A fw_standby -m owner --uid-owner 12345 -j DROP\nCOMMIT\n" }
126     };
127     mFw.setUidRule(STANDBY, 12345, DENY);
128     expectIptablesRestoreCommands(expected);
129 }
130 
TEST_F(FirewallControllerTest,TestSetDozeRule)131 TEST_F(FirewallControllerTest, TestSetDozeRule) {
132     ExpectedIptablesCommands expected = {
133         { V4V6, "*filter\n-I fw_dozable -m owner --uid-owner 54321 -j RETURN\nCOMMIT\n" }
134     };
135     mFw.setUidRule(DOZABLE, 54321, ALLOW);
136     expectIptablesRestoreCommands(expected);
137 
138     expected = {
139         { V4V6, "*filter\n-D fw_dozable -m owner --uid-owner 54321 -j RETURN\nCOMMIT\n" }
140     };
141     mFw.setUidRule(DOZABLE, 54321, DENY);
142     expectIptablesRestoreCommands(expected);
143 }
144 
TEST_F(FirewallControllerTest,TestSetFirewallRule)145 TEST_F(FirewallControllerTest, TestSetFirewallRule) {
146     ExpectedIptablesCommands expected = {
147         { V4V6, "*filter\n"
148                 "-A fw_INPUT -m owner --uid-owner 54321 -j DROP\n"
149                 "-A fw_OUTPUT -m owner --uid-owner 54321 -j DROP\n"
150                 "COMMIT\n" }
151     };
152     mFw.setUidRule(NONE, 54321, DENY);
153     expectIptablesRestoreCommands(expected);
154 
155     expected = {
156         { V4V6, "*filter\n"
157                 "-D fw_INPUT -m owner --uid-owner 54321 -j DROP\n"
158                 "-D fw_OUTPUT -m owner --uid-owner 54321 -j DROP\n"
159                 "COMMIT\n" }
160     };
161     mFw.setUidRule(NONE, 54321, ALLOW);
162     expectIptablesRestoreCommands(expected);
163 }
164 
TEST_F(FirewallControllerTest,TestReplaceWhitelistUidRule)165 TEST_F(FirewallControllerTest, TestReplaceWhitelistUidRule) {
166     std::string expected =
167             "*filter\n"
168             ":FW_whitechain -\n"
169             "-A FW_whitechain -m owner --uid-owner 10023 -j RETURN\n"
170             "-A FW_whitechain -m owner --uid-owner 10059 -j RETURN\n"
171             "-A FW_whitechain -m owner --uid-owner 10124 -j RETURN\n"
172             "-A FW_whitechain -m owner --uid-owner 10111 -j RETURN\n"
173             "-A FW_whitechain -m owner --uid-owner 110122 -j RETURN\n"
174             "-A FW_whitechain -m owner --uid-owner 210153 -j RETURN\n"
175             "-A FW_whitechain -m owner --uid-owner 210024 -j RETURN\n"
176             "-A FW_whitechain -m owner --uid-owner 0-9999 -j RETURN\n"
177             "-A FW_whitechain -m owner ! --uid-owner 0-4294967294 -j RETURN\n"
178             "-A FW_whitechain -p esp -j RETURN\n"
179             "-A FW_whitechain -i lo -j RETURN\n"
180             "-A FW_whitechain -o lo -j RETURN\n"
181             "-A FW_whitechain -p tcp --tcp-flags RST RST -j RETURN\n"
182             "-A FW_whitechain -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
183             "-A FW_whitechain -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
184             "-A FW_whitechain -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
185             "-A FW_whitechain -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
186             "-A FW_whitechain -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
187             "-A FW_whitechain -p icmpv6 --icmpv6-type redirect -j RETURN\n"
188             "-A FW_whitechain -j DROP\n"
189             "COMMIT\n";
190 
191     std::vector<int32_t> uids = { 10023, 10059, 10124, 10111, 110122, 210153, 210024 };
192     EXPECT_EQ(expected, makeUidRules(V6, "FW_whitechain", true, uids));
193 }
194 
TEST_F(FirewallControllerTest,TestReplaceBlacklistUidRule)195 TEST_F(FirewallControllerTest, TestReplaceBlacklistUidRule) {
196     std::string expected =
197             "*filter\n"
198             ":FW_blackchain -\n"
199             "-A FW_blackchain -i lo -j RETURN\n"
200             "-A FW_blackchain -o lo -j RETURN\n"
201             "-A FW_blackchain -p tcp --tcp-flags RST RST -j RETURN\n"
202             "-A FW_blackchain -m owner --uid-owner 10023 -j DROP\n"
203             "-A FW_blackchain -m owner --uid-owner 10059 -j DROP\n"
204             "-A FW_blackchain -m owner --uid-owner 10124 -j DROP\n"
205             "COMMIT\n";
206 
207     std::vector<int32_t> uids = { 10023, 10059, 10124 };
208     EXPECT_EQ(expected, makeUidRules(V4 ,"FW_blackchain", false, uids));
209 }
210 
TEST_F(FirewallControllerTest,TestEnableChildChains)211 TEST_F(FirewallControllerTest, TestEnableChildChains) {
212     std::vector<std::string> expected = {
213         "*filter\n"
214         "-A fw_INPUT -j fw_dozable\n"
215         "-A fw_OUTPUT -j fw_dozable\n"
216         "COMMIT\n"
217     };
218     EXPECT_EQ(0, mFw.enableChildChains(DOZABLE, true));
219     expectIptablesRestoreCommands(expected);
220 
221     expected = {
222         "*filter\n"
223         "-D fw_INPUT -j fw_powersave\n"
224         "-D fw_OUTPUT -j fw_powersave\n"
225         "COMMIT\n"
226     };
227     EXPECT_EQ(0, mFw.enableChildChains(POWERSAVE, false));
228     expectIptablesRestoreCommands(expected);
229 }
230 
TEST_F(FirewallControllerTest,TestFirewall)231 TEST_F(FirewallControllerTest, TestFirewall) {
232     std::vector<std::string> enableCommands = {
233         "*filter\n"
234         "-A fw_INPUT -j DROP\n"
235         "-A fw_OUTPUT -j REJECT\n"
236         "-A fw_FORWARD -j REJECT\n"
237         "COMMIT\n"
238     };
239     std::vector<std::string> disableCommands = {
240         "*filter\n"
241         ":fw_INPUT -\n"
242         ":fw_OUTPUT -\n"
243         ":fw_FORWARD -\n"
244         "COMMIT\n"
245     };
246     std::vector<std::string> noCommands = {};
247 
248     EXPECT_EQ(0, mFw.resetFirewall());
249     expectIptablesRestoreCommands(disableCommands);
250 
251     EXPECT_EQ(0, mFw.resetFirewall());
252     expectIptablesRestoreCommands(disableCommands);
253 
254     EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
255     expectIptablesRestoreCommands(disableCommands);
256 
257     EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
258     expectIptablesRestoreCommands(noCommands);
259 
260     std::vector<std::string> disableEnableCommands;
261     disableEnableCommands.insert(
262             disableEnableCommands.end(), disableCommands.begin(), disableCommands.end());
263     disableEnableCommands.insert(
264             disableEnableCommands.end(), enableCommands.begin(), enableCommands.end());
265 
266     EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
267     expectIptablesRestoreCommands(disableEnableCommands);
268 
269     std::vector<std::string> ifaceCommands = {
270         "*filter\n"
271         "-I fw_INPUT -i rmnet_data0 -j RETURN\n"
272         "-I fw_OUTPUT -o rmnet_data0 -j RETURN\n"
273         "COMMIT\n"
274     };
275     EXPECT_EQ(0, mFw.setInterfaceRule("rmnet_data0", ALLOW));
276     expectIptablesRestoreCommands(ifaceCommands);
277 
278     EXPECT_EQ(0, mFw.setInterfaceRule("rmnet_data0", ALLOW));
279     expectIptablesRestoreCommands(noCommands);
280 
281     ifaceCommands = {
282         "*filter\n"
283         "-D fw_INPUT -i rmnet_data0 -j RETURN\n"
284         "-D fw_OUTPUT -o rmnet_data0 -j RETURN\n"
285         "COMMIT\n"
286     };
287     EXPECT_EQ(0, mFw.setInterfaceRule("rmnet_data0", DENY));
288     expectIptablesRestoreCommands(ifaceCommands);
289 
290     EXPECT_EQ(0, mFw.setInterfaceRule("rmnet_data0", DENY));
291     expectIptablesRestoreCommands(noCommands);
292 
293     EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
294     expectIptablesRestoreCommands(noCommands);
295 
296     EXPECT_EQ(0, mFw.resetFirewall());
297     expectIptablesRestoreCommands(disableCommands);
298 
299     // TODO: calling resetFirewall and then setFirewallType(WHITELIST) does
300     // nothing. This seems like a clear bug.
301     EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
302     expectIptablesRestoreCommands(noCommands);
303 }
304 
TEST_F(FirewallControllerTest,TestDiscoverMaximumValidUid)305 TEST_F(FirewallControllerTest, TestDiscoverMaximumValidUid) {
306     struct {
307         const std::string description;
308         const std::string content;
309         const uint32_t expected;
310     } testCases[] = {
311             {
312                     .description = "root namespace case",
313                     .content = "         0          0 4294967295",
314                     .expected = 4294967294,
315             },
316             {
317                     .description = "container namespace case",
318                     .content = "         0     655360       5000\n"
319                                "      5000        600         50\n"
320                                "      5050     660410    1994950\n",
321                     .expected = 1999999,
322             },
323             {
324                     .description = "garbage content case",
325                     .content = "garbage",
326                     .expected = 4294967294,
327             },
328             {
329                     .description = "no content case",
330                     .content = "",
331                     .expected = 4294967294,
332             },
333     };
334 
335     const std::string tempFile = "/data/local/tmp/fake_uid_mapping";
336 
337     for (const auto& test : testCases) {
338         EXPECT_TRUE(WriteStringToFile(test.content, tempFile, false));
339         uint32_t got = FirewallController::discoverMaximumValidUid(tempFile);
340         EXPECT_EQ(0, remove(tempFile.c_str()));
341         if (got != test.expected) {
342             FAIL() << test.description << ":\n"
343                    << test.content << "\ngot " << got << ", but expected " << test.expected;
344         }
345     }
346 
347     // Also check when the file is not defined
348     EXPECT_NE(0, access(tempFile.c_str(), F_OK));
349     EXPECT_EQ(4294967294, FirewallController::discoverMaximumValidUid(tempFile));
350 }
351 
352 }  // namespace net
353 }  // namespace android
354