1 /*
2  * Copyright (C) 2017 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 #define LOG_TAG "VtsOffloadConfigV1_0TargetTest"
18 
19 #include <android-base/stringprintf.h>
20 #include <android-base/unique_fd.h>
21 #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
22 #include <gtest/gtest.h>
23 #include <hidl/GtestPrinter.h>
24 #include <hidl/ServiceManagement.h>
25 #include <linux/netfilter/nfnetlink.h>
26 #include <linux/netlink.h>
27 #include <linux/rtnetlink.h>
28 #include <log/log.h>
29 #include <sys/socket.h>
30 #include <unistd.h>
31 #include <set>
32 
33 using android::base::StringPrintf;
34 using android::base::unique_fd;
35 using android::hardware::hidl_handle;
36 using android::hardware::hidl_string;
37 using android::hardware::Return;
38 using android::hardware::tetheroffload::config::V1_0::IOffloadConfig;
39 using android::hardware::Void;
40 using android::sp;
41 
42 #define ASSERT_TRUE_CALLBACK \
43     [&](bool success, const hidl_string& errMsg) { ASSERT_TRUE(success) << errMsg.c_str(); }
44 
45 #define ASSERT_FALSE_CALLBACK \
46     [&](bool success, const hidl_string& errMsg) { ASSERT_FALSE(success) << errMsg.c_str(); }
47 
48 const unsigned kFd1Groups = NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY;
49 const unsigned kFd2Groups = NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY;
50 
asSockaddr(const sockaddr_nl * nladdr)51 inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr) {
52     return reinterpret_cast<const sockaddr*>(nladdr);
53 }
54 
netlinkSocket(int protocol,unsigned groups)55 int netlinkSocket(int protocol, unsigned groups) {
56     unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, protocol));
57     if (s.get() < 0) {
58         return -errno;
59     }
60 
61     const struct sockaddr_nl bind_addr = {
62         .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
63     };
64     if (::bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) {
65         return -errno;
66     }
67 
68     const struct sockaddr_nl kernel_addr = {
69         .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
70     };
71     if (::connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
72         return -errno;
73     }
74 
75     return s.release();
76 }
77 
netlinkSocket(unsigned groups)78 int netlinkSocket(unsigned groups) {
79     return netlinkSocket(NETLINK_NETFILTER, groups);
80 }
81 
82 class OffloadConfigHidlTest : public testing::TestWithParam<std::string> {
83    public:
SetUp()84     virtual void SetUp() override {
85         config = IOffloadConfig::getService(GetParam());
86         ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
87     }
88 
TearDown()89     virtual void TearDown() override {}
90 
91     sp<IOffloadConfig> config;
92 };
93 
94 // Ensure handles can be set with correct socket options.
TEST_P(OffloadConfigHidlTest,TestSetHandles)95 TEST_P(OffloadConfigHidlTest, TestSetHandles) {
96     // Try multiple times in a row to see if it provokes file descriptor leaks.
97     for (int i = 0; i < 1024; i++) {
98         unique_fd fd1(netlinkSocket(kFd1Groups));
99         if (fd1.get() < 0) {
100             ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
101             FAIL();
102         }
103         native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
104         nativeHandle1->data[0] = fd1.release();
105         hidl_handle h1;
106         h1.setTo(nativeHandle1, true);
107 
108         unique_fd fd2(netlinkSocket(kFd2Groups));
109         if (fd2.get() < 0) {
110             ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
111             FAIL();
112         }
113         native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
114         nativeHandle2->data[0] = fd2.release();
115         hidl_handle h2;
116         h2.setTo(nativeHandle2, true);
117 
118         const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK);
119         ASSERT_TRUE(ret.isOk());
120     }
121 }
122 
123 // Passing a handle without an associated file descriptor should return an error
124 // (e.g. "Failed Input Checks"). Check that this occurs when both FDs are empty.
TEST_P(OffloadConfigHidlTest,TestSetHandleNone)125 TEST_P(OffloadConfigHidlTest, TestSetHandleNone) {
126     native_handle_t* const nativeHandle1 = native_handle_create(0, 0);
127     hidl_handle h1;
128     h1.setTo(nativeHandle1, true);
129     native_handle_t* const nativeHandle2 = native_handle_create(0, 0);
130     hidl_handle h2;
131     h2.setTo(nativeHandle2, true);
132 
133     const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK);
134     ASSERT_TRUE(ret.isOk());
135 }
136 
137 // Passing a handle without an associated file descriptor should return an error
138 // (e.g. "Failed Input Checks"). Check that this occurs when FD2 is empty.
TEST_P(OffloadConfigHidlTest,TestSetHandle1Only)139 TEST_P(OffloadConfigHidlTest, TestSetHandle1Only) {
140     unique_fd fd1(netlinkSocket(kFd1Groups));
141     if (fd1.get() < 0) {
142         ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
143         FAIL();
144     }
145     native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
146     nativeHandle1->data[0] = fd1.release();
147     hidl_handle h1;
148     h1.setTo(nativeHandle1, true);
149 
150     native_handle_t* const nativeHandle2 = native_handle_create(0, 0);
151     hidl_handle h2;
152     h2.setTo(nativeHandle2, true);
153 
154     const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK);
155     ASSERT_TRUE(ret.isOk());
156 }
157 
158 // Passing a handle without an associated file descriptor should return an error
159 // (e.g. "Failed Input Checks"). Check that this occurs when FD1 is empty.
TEST_P(OffloadConfigHidlTest,TestSetHandle2OnlyNotOk)160 TEST_P(OffloadConfigHidlTest, TestSetHandle2OnlyNotOk) {
161     native_handle_t* const nativeHandle1 = native_handle_create(0, 0);
162     hidl_handle h1;
163     h1.setTo(nativeHandle1, true);
164 
165     unique_fd fd2(netlinkSocket(kFd2Groups));
166     if (fd2.get() < 0) {
167         ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
168         FAIL();
169     }
170     native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
171     nativeHandle2->data[0] = fd2.release();
172     hidl_handle h2;
173     h2.setTo(nativeHandle2, true);
174 
175     const Return<void> ret = config->setHandles(h1, h2, ASSERT_FALSE_CALLBACK);
176     ASSERT_TRUE(ret.isOk());
177 }
178 
179 INSTANTIATE_TEST_SUITE_P(
180         PerInstance, OffloadConfigHidlTest,
181         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
182         android::hardware::PrintInstanceNameToString);
183