1*8542734aSAndroid Build Coastguard Worker /*
2*8542734aSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*8542734aSAndroid Build Coastguard Worker *
4*8542734aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*8542734aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*8542734aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*8542734aSAndroid Build Coastguard Worker *
8*8542734aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*8542734aSAndroid Build Coastguard Worker *
10*8542734aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*8542734aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*8542734aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8542734aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*8542734aSAndroid Build Coastguard Worker * limitations under the License.
15*8542734aSAndroid Build Coastguard Worker */
16*8542734aSAndroid Build Coastguard Worker
17*8542734aSAndroid Build Coastguard Worker #include <string>
18*8542734aSAndroid Build Coastguard Worker #include <vector>
19*8542734aSAndroid Build Coastguard Worker
20*8542734aSAndroid Build Coastguard Worker #include <errno.h>
21*8542734aSAndroid Build Coastguard Worker #include <stdio.h>
22*8542734aSAndroid Build Coastguard Worker #include <stdlib.h>
23*8542734aSAndroid Build Coastguard Worker #include <string.h>
24*8542734aSAndroid Build Coastguard Worker
25*8542734aSAndroid Build Coastguard Worker #define LOG_TAG "StrictController"
26*8542734aSAndroid Build Coastguard Worker #define LOG_NDEBUG 0
27*8542734aSAndroid Build Coastguard Worker #include <log/log.h>
28*8542734aSAndroid Build Coastguard Worker
29*8542734aSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
30*8542734aSAndroid Build Coastguard Worker #include <android-base/strings.h>
31*8542734aSAndroid Build Coastguard Worker
32*8542734aSAndroid Build Coastguard Worker #include "ConnmarkFlags.h"
33*8542734aSAndroid Build Coastguard Worker #include "NetdConstants.h"
34*8542734aSAndroid Build Coastguard Worker #include "StrictController.h"
35*8542734aSAndroid Build Coastguard Worker
36*8542734aSAndroid Build Coastguard Worker auto StrictController::execIptablesRestore = ::execIptablesRestore;
37*8542734aSAndroid Build Coastguard Worker
38*8542734aSAndroid Build Coastguard Worker const char* StrictController::LOCAL_OUTPUT = "st_OUTPUT";
39*8542734aSAndroid Build Coastguard Worker const char* StrictController::LOCAL_CLEAR_DETECT = "st_clear_detect";
40*8542734aSAndroid Build Coastguard Worker const char* StrictController::LOCAL_CLEAR_CAUGHT = "st_clear_caught";
41*8542734aSAndroid Build Coastguard Worker const char* StrictController::LOCAL_PENALTY_LOG = "st_penalty_log";
42*8542734aSAndroid Build Coastguard Worker const char* StrictController::LOCAL_PENALTY_REJECT = "st_penalty_reject";
43*8542734aSAndroid Build Coastguard Worker
44*8542734aSAndroid Build Coastguard Worker using android::base::Join;
45*8542734aSAndroid Build Coastguard Worker using android::base::StringPrintf;
46*8542734aSAndroid Build Coastguard Worker
StrictController(void)47*8542734aSAndroid Build Coastguard Worker StrictController::StrictController(void) {
48*8542734aSAndroid Build Coastguard Worker }
49*8542734aSAndroid Build Coastguard Worker
setupIptablesHooks(void)50*8542734aSAndroid Build Coastguard Worker int StrictController::setupIptablesHooks(void) {
51*8542734aSAndroid Build Coastguard Worker char connmarkFlagAccept[16];
52*8542734aSAndroid Build Coastguard Worker char connmarkFlagReject[16];
53*8542734aSAndroid Build Coastguard Worker char connmarkFlagTestAccept[32];
54*8542734aSAndroid Build Coastguard Worker char connmarkFlagTestReject[32];
55*8542734aSAndroid Build Coastguard Worker sprintf(connmarkFlagAccept, "0x%x", ConnmarkFlags::STRICT_RESOLVED_ACCEPT);
56*8542734aSAndroid Build Coastguard Worker sprintf(connmarkFlagReject, "0x%x", ConnmarkFlags::STRICT_RESOLVED_REJECT);
57*8542734aSAndroid Build Coastguard Worker sprintf(connmarkFlagTestAccept, "0x%x/0x%x",
58*8542734aSAndroid Build Coastguard Worker ConnmarkFlags::STRICT_RESOLVED_ACCEPT,
59*8542734aSAndroid Build Coastguard Worker ConnmarkFlags::STRICT_RESOLVED_ACCEPT);
60*8542734aSAndroid Build Coastguard Worker sprintf(connmarkFlagTestReject, "0x%x/0x%x",
61*8542734aSAndroid Build Coastguard Worker ConnmarkFlags::STRICT_RESOLVED_REJECT,
62*8542734aSAndroid Build Coastguard Worker ConnmarkFlags::STRICT_RESOLVED_REJECT);
63*8542734aSAndroid Build Coastguard Worker
64*8542734aSAndroid Build Coastguard Worker resetChains();
65*8542734aSAndroid Build Coastguard Worker
66*8542734aSAndroid Build Coastguard Worker int res = 0;
67*8542734aSAndroid Build Coastguard Worker std::vector<std::string> v4, v6;
68*8542734aSAndroid Build Coastguard Worker
69*8542734aSAndroid Build Coastguard Worker #define CMD_V4(...) { auto cmd = StringPrintf(__VA_ARGS__); v4.push_back(cmd); }
70*8542734aSAndroid Build Coastguard Worker #define CMD_V6(...) { auto cmd = StringPrintf(__VA_ARGS__); v6.push_back(cmd); }
71*8542734aSAndroid Build Coastguard Worker #define CMD_V4V6(...) { CMD_V4(__VA_ARGS__); CMD_V6(__VA_ARGS__); };
72*8542734aSAndroid Build Coastguard Worker
73*8542734aSAndroid Build Coastguard Worker CMD_V4V6("*filter");
74*8542734aSAndroid Build Coastguard Worker
75*8542734aSAndroid Build Coastguard Worker // Chain triggered when cleartext socket detected and penalty is log
76*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -j CONNMARK --or-mark %s", LOCAL_PENALTY_LOG, connmarkFlagAccept);
77*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -j NFLOG --nflog-group 0", LOCAL_PENALTY_LOG);
78*8542734aSAndroid Build Coastguard Worker
79*8542734aSAndroid Build Coastguard Worker // Chain triggered when cleartext socket detected and penalty is reject
80*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -j CONNMARK --or-mark %s", LOCAL_PENALTY_REJECT, connmarkFlagReject);
81*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -j NFLOG --nflog-group 0", LOCAL_PENALTY_REJECT);
82*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -j REJECT", LOCAL_PENALTY_REJECT);
83*8542734aSAndroid Build Coastguard Worker
84*8542734aSAndroid Build Coastguard Worker // We use a high-order mark bit to keep track of connections that we've already resolved.
85*8542734aSAndroid Build Coastguard Worker // Quickly skip connections that we've already resolved
86*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -m connmark --mark %s -j REJECT", LOCAL_CLEAR_DETECT, connmarkFlagTestReject);
87*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -m connmark --mark %s -j RETURN", LOCAL_CLEAR_DETECT, connmarkFlagTestAccept);
88*8542734aSAndroid Build Coastguard Worker
89*8542734aSAndroid Build Coastguard Worker // Look for IPv4 TCP/UDP connections with TLS/DTLS header
90*8542734aSAndroid Build Coastguard Worker const char *u32;
91*8542734aSAndroid Build Coastguard Worker u32 = "0>>22&0x3C@ 12>>26&0x3C@ 0&0xFFFF0000=0x16030000 &&"
92*8542734aSAndroid Build Coastguard Worker "0>>22&0x3C@ 12>>26&0x3C@ 4&0x00FF0000=0x00010000";
93*8542734aSAndroid Build Coastguard Worker CMD_V4("-A %s -p tcp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
94*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
95*8542734aSAndroid Build Coastguard Worker
96*8542734aSAndroid Build Coastguard Worker u32 = "0>>22&0x3C@ 8&0xFFFF0000=0x16FE0000 &&"
97*8542734aSAndroid Build Coastguard Worker "0>>22&0x3C@ 20&0x00FF0000=0x00010000";
98*8542734aSAndroid Build Coastguard Worker CMD_V4("-A %s -p udp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
99*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
100*8542734aSAndroid Build Coastguard Worker
101*8542734aSAndroid Build Coastguard Worker // Look for IPv6 TCP/UDP connections with TLS/DTLS header. The IPv6 header
102*8542734aSAndroid Build Coastguard Worker // doesn't have an IHL field to shift with, so we have to manually add in
103*8542734aSAndroid Build Coastguard Worker // the 40-byte offset at every step.
104*8542734aSAndroid Build Coastguard Worker u32 = "52>>26&0x3C@ 40&0xFFFF0000=0x16030000 &&"
105*8542734aSAndroid Build Coastguard Worker "52>>26&0x3C@ 44&0x00FF0000=0x00010000";
106*8542734aSAndroid Build Coastguard Worker CMD_V6("-A %s -p tcp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
107*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
108*8542734aSAndroid Build Coastguard Worker
109*8542734aSAndroid Build Coastguard Worker u32 = "48&0xFFFF0000=0x16FE0000 &&"
110*8542734aSAndroid Build Coastguard Worker "60&0x00FF0000=0x00010000";
111*8542734aSAndroid Build Coastguard Worker CMD_V6("-A %s -p udp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
112*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
113*8542734aSAndroid Build Coastguard Worker
114*8542734aSAndroid Build Coastguard Worker // Skip newly classified connections from above
115*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -m connmark --mark %s -j RETURN", LOCAL_CLEAR_DETECT, connmarkFlagTestAccept);
116*8542734aSAndroid Build Coastguard Worker
117*8542734aSAndroid Build Coastguard Worker // Handle TCP/UDP payloads that didn't match TLS/DTLS filters above,
118*8542734aSAndroid Build Coastguard Worker // which means we've probably found cleartext data. The TCP variant
119*8542734aSAndroid Build Coastguard Worker // depends on u32 returning false when we try reading into the message
120*8542734aSAndroid Build Coastguard Worker // body to ignore empty ACK packets.
121*8542734aSAndroid Build Coastguard Worker u32 = "0>>22&0x3C@ 12>>26&0x3C@ 0&0x0=0x0";
122*8542734aSAndroid Build Coastguard Worker CMD_V4("-A %s -p tcp -m state --state ESTABLISHED -m u32 --u32 \"%s\" -j %s",
123*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_DETECT, u32, LOCAL_CLEAR_CAUGHT);
124*8542734aSAndroid Build Coastguard Worker
125*8542734aSAndroid Build Coastguard Worker u32 = "52>>26&0x3C@ 40&0x0=0x0";
126*8542734aSAndroid Build Coastguard Worker CMD_V6("-A %s -p tcp -m state --state ESTABLISHED -m u32 --u32 \"%s\" -j %s",
127*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_DETECT, u32, LOCAL_CLEAR_CAUGHT);
128*8542734aSAndroid Build Coastguard Worker
129*8542734aSAndroid Build Coastguard Worker CMD_V4V6("-A %s -p udp -j %s", LOCAL_CLEAR_DETECT, LOCAL_CLEAR_CAUGHT);
130*8542734aSAndroid Build Coastguard Worker CMD_V4V6("COMMIT\n");
131*8542734aSAndroid Build Coastguard Worker
132*8542734aSAndroid Build Coastguard Worker res |= execIptablesRestore(V4, Join(v4, '\n'));
133*8542734aSAndroid Build Coastguard Worker res |= execIptablesRestore(V6, Join(v6, '\n'));
134*8542734aSAndroid Build Coastguard Worker
135*8542734aSAndroid Build Coastguard Worker #undef CMD_V4
136*8542734aSAndroid Build Coastguard Worker #undef CMD_V6
137*8542734aSAndroid Build Coastguard Worker #undef CMD_V4V6
138*8542734aSAndroid Build Coastguard Worker
139*8542734aSAndroid Build Coastguard Worker return res ? -EREMOTEIO : 0;
140*8542734aSAndroid Build Coastguard Worker }
141*8542734aSAndroid Build Coastguard Worker
resetChains(void)142*8542734aSAndroid Build Coastguard Worker int StrictController::resetChains(void) {
143*8542734aSAndroid Build Coastguard Worker // Flush any existing rules
144*8542734aSAndroid Build Coastguard Worker #define CLEAR_CHAIN(x) StringPrintf(":%s -", (x))
145*8542734aSAndroid Build Coastguard Worker std::vector<std::string> commandList = {
146*8542734aSAndroid Build Coastguard Worker "*filter",
147*8542734aSAndroid Build Coastguard Worker CLEAR_CHAIN(LOCAL_OUTPUT),
148*8542734aSAndroid Build Coastguard Worker CLEAR_CHAIN(LOCAL_PENALTY_LOG),
149*8542734aSAndroid Build Coastguard Worker CLEAR_CHAIN(LOCAL_PENALTY_REJECT),
150*8542734aSAndroid Build Coastguard Worker CLEAR_CHAIN(LOCAL_CLEAR_CAUGHT),
151*8542734aSAndroid Build Coastguard Worker CLEAR_CHAIN(LOCAL_CLEAR_DETECT),
152*8542734aSAndroid Build Coastguard Worker "COMMIT\n"
153*8542734aSAndroid Build Coastguard Worker };
154*8542734aSAndroid Build Coastguard Worker const std::string commands = Join(commandList, '\n');
155*8542734aSAndroid Build Coastguard Worker return (execIptablesRestore(V4V6, commands) == 0) ? 0 : -EREMOTEIO;
156*8542734aSAndroid Build Coastguard Worker #undef CLEAR_CHAIN
157*8542734aSAndroid Build Coastguard Worker }
158*8542734aSAndroid Build Coastguard Worker
setUidCleartextPenalty(uid_t uid,StrictPenalty penalty)159*8542734aSAndroid Build Coastguard Worker int StrictController::setUidCleartextPenalty(uid_t uid, StrictPenalty penalty) {
160*8542734aSAndroid Build Coastguard Worker // When a penalty is set, we don't know what penalty the UID previously had. In order to be able
161*8542734aSAndroid Build Coastguard Worker // to clear the previous penalty without causing an iptables error by deleting rules that don't
162*8542734aSAndroid Build Coastguard Worker // exist, put each UID's rules in a chain specific to that UID. That way, the commands we need
163*8542734aSAndroid Build Coastguard Worker // to run to clear the previous penalty don't depend on what the penalty actually was - all we
164*8542734aSAndroid Build Coastguard Worker // need to do is clear the chain.
165*8542734aSAndroid Build Coastguard Worker std::string perUidChain = StringPrintf("st_clear_caught_%u", uid);
166*8542734aSAndroid Build Coastguard Worker
167*8542734aSAndroid Build Coastguard Worker std::vector<std::string> commands;
168*8542734aSAndroid Build Coastguard Worker if (penalty == ACCEPT) {
169*8542734aSAndroid Build Coastguard Worker // Clean up any old rules
170*8542734aSAndroid Build Coastguard Worker commands = {
171*8542734aSAndroid Build Coastguard Worker "*filter",
172*8542734aSAndroid Build Coastguard Worker StringPrintf("-D %s -m owner --uid-owner %d -j %s",
173*8542734aSAndroid Build Coastguard Worker LOCAL_OUTPUT, uid, LOCAL_CLEAR_DETECT),
174*8542734aSAndroid Build Coastguard Worker StringPrintf("-D %s -m owner --uid-owner %d -j %s",
175*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_CAUGHT, uid, perUidChain.c_str()),
176*8542734aSAndroid Build Coastguard Worker StringPrintf("-F %s", perUidChain.c_str()),
177*8542734aSAndroid Build Coastguard Worker StringPrintf("-X %s", perUidChain.c_str()),
178*8542734aSAndroid Build Coastguard Worker };
179*8542734aSAndroid Build Coastguard Worker } else {
180*8542734aSAndroid Build Coastguard Worker // Always take a detour to investigate this UID
181*8542734aSAndroid Build Coastguard Worker commands.push_back("*filter");
182*8542734aSAndroid Build Coastguard Worker commands.push_back(StringPrintf(":%s -", perUidChain.c_str()));
183*8542734aSAndroid Build Coastguard Worker commands.push_back(StringPrintf("-I %s -m owner --uid-owner %d -j %s",
184*8542734aSAndroid Build Coastguard Worker LOCAL_OUTPUT, uid, LOCAL_CLEAR_DETECT));
185*8542734aSAndroid Build Coastguard Worker commands.push_back(StringPrintf("-I %s -m owner --uid-owner %d -j %s",
186*8542734aSAndroid Build Coastguard Worker LOCAL_CLEAR_CAUGHT, uid, perUidChain.c_str()));
187*8542734aSAndroid Build Coastguard Worker
188*8542734aSAndroid Build Coastguard Worker if (penalty == LOG) {
189*8542734aSAndroid Build Coastguard Worker commands.push_back(StringPrintf("-A %s -j %s", perUidChain.c_str(), LOCAL_PENALTY_LOG));
190*8542734aSAndroid Build Coastguard Worker } else if (penalty == REJECT) {
191*8542734aSAndroid Build Coastguard Worker commands.push_back(StringPrintf("-A %s -j %s", perUidChain.c_str(),
192*8542734aSAndroid Build Coastguard Worker LOCAL_PENALTY_REJECT));
193*8542734aSAndroid Build Coastguard Worker }
194*8542734aSAndroid Build Coastguard Worker }
195*8542734aSAndroid Build Coastguard Worker commands.push_back("COMMIT\n");
196*8542734aSAndroid Build Coastguard Worker
197*8542734aSAndroid Build Coastguard Worker return (execIptablesRestore(V4V6, Join(commands, "\n")) == 0) ? 0 : -EREMOTEIO;
198*8542734aSAndroid Build Coastguard Worker }
199