1 /*
2  * Copyright (C) 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 specic language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "libappfuse/FuseBridgeLoop.h"
18 
19 #include <sys/socket.h>
20 
21 #include <sstream>
22 #include <thread>
23 
24 #include <android-base/logging.h>
25 #include <android-base/unique_fd.h>
26 #include <gtest/gtest.h>
27 
28 namespace android {
29 namespace fuse {
30 namespace {
31 
32 class Callback : public FuseBridgeLoopCallback {
33  public:
34   bool mounted;
35   bool closed;
Callback()36   Callback() : mounted(false), closed(false) {}
37 
OnMount(int)38   void OnMount(int /*mount_id*/) override { mounted = true; }
39 
OnClosed(int)40   void OnClosed(int /* mount_id */) override { closed = true; }
41 };
42 
43 class FuseBridgeLoopTest : public ::testing::Test {
44  protected:
45   base::unique_fd dev_sockets_[2];
46   base::unique_fd proxy_sockets_[2];
47   Callback callback_;
48   std::thread thread_;
49 
50   FuseRequest request_;
51   FuseResponse response_;
52 
SetUp()53   void SetUp() override {
54     base::SetMinimumLogSeverity(base::VERBOSE);
55     ASSERT_TRUE(SetupMessageSockets(&dev_sockets_));
56     ASSERT_TRUE(SetupMessageSockets(&proxy_sockets_));
57     thread_ = std::thread([this] {
58         FuseBridgeLoop loop;
59         loop.AddBridge(1, std::move(dev_sockets_[1]), std::move(proxy_sockets_[0]));
60         loop.Start(&callback_);
61     });
62   }
63 
CheckNotImpl(uint32_t opcode)64   void CheckNotImpl(uint32_t opcode) {
65     SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
66 
67     memset(&request_, 0, sizeof(FuseRequest));
68     request_.header.opcode = opcode;
69     request_.header.len = sizeof(fuse_in_header);
70     request_.header.unique = 1;
71     ASSERT_TRUE(request_.Write(dev_sockets_[0]));
72 
73     memset(&response_, 0, sizeof(FuseResponse));
74     ASSERT_TRUE(response_.Read(dev_sockets_[0]));
75     EXPECT_EQ(-ENOSYS, response_.header.error);
76   }
77 
CheckProxy(uint32_t opcode)78   void CheckProxy(uint32_t opcode) {
79     SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
80 
81     memset(&request_, 0, sizeof(FuseRequest));
82     request_.header.opcode = opcode;
83     request_.header.unique = opcode; // Use opcode as unique.
84     request_.header.len = sizeof(fuse_in_header);
85     ASSERT_TRUE(request_.Write(dev_sockets_[0]));
86 
87     memset(&request_, 0, sizeof(FuseRequest));
88     ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
89     EXPECT_EQ(opcode, request_.header.opcode);
90     EXPECT_EQ(opcode, request_.header.unique);
91 
92     memset(&response_, 0, sizeof(FuseResponse));
93     response_.header.len = sizeof(fuse_out_header);
94     response_.header.unique = opcode;  // Use opcode as unique.
95     response_.header.error = kFuseSuccess;
96     ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
97 
98     memset(&response_, 0, sizeof(FuseResponse));
99     ASSERT_TRUE(response_.Read(dev_sockets_[0]));
100     EXPECT_EQ(opcode, response_.header.unique);
101     EXPECT_EQ(kFuseSuccess, response_.header.error);
102   }
103 
SendInitRequest(uint64_t unique)104   void SendInitRequest(uint64_t unique) {
105     memset(&request_, 0, sizeof(FuseRequest));
106     request_.header.opcode = FUSE_INIT;
107     request_.header.unique = unique;
108     request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
109     request_.init_in.major = FUSE_KERNEL_VERSION;
110     request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
111     ASSERT_TRUE(request_.Write(dev_sockets_[0]));
112   }
113 
Close()114   void Close() {
115     dev_sockets_[0].reset();
116     dev_sockets_[1].reset();
117     proxy_sockets_[0].reset();
118     proxy_sockets_[1].reset();
119     if (thread_.joinable()) {
120       thread_.join();
121     }
122     ASSERT_TRUE(callback_.closed);
123   }
124 
TearDown()125   void TearDown() override {
126     Close();
127   }
128 };
129 
130 } //  namespace
131 
TEST_F(FuseBridgeLoopTest,FuseInit)132 TEST_F(FuseBridgeLoopTest, FuseInit) {
133   SendInitRequest(1u);
134 
135   memset(&response_, 0, sizeof(FuseResponse));
136   ASSERT_TRUE(response_.Read(dev_sockets_[0]));
137   EXPECT_EQ(kFuseSuccess, response_.header.error);
138   EXPECT_EQ(1u, response_.header.unique);
139 
140   // Unmount.
141   Close();
142   EXPECT_TRUE(callback_.mounted);
143 }
144 
TEST_F(FuseBridgeLoopTest,FuseForget)145 TEST_F(FuseBridgeLoopTest, FuseForget) {
146   memset(&request_, 0, sizeof(FuseRequest));
147   request_.header.opcode = FUSE_FORGET;
148   request_.header.unique = 1u;
149   request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
150   ASSERT_TRUE(request_.Write(dev_sockets_[0]));
151 
152   SendInitRequest(2u);
153 
154   memset(&response_, 0, sizeof(FuseResponse));
155   ASSERT_TRUE(response_.Read(dev_sockets_[0]));
156   EXPECT_EQ(2u, response_.header.unique) <<
157       "The loop must not respond to FUSE_FORGET";
158 }
159 
TEST_F(FuseBridgeLoopTest,FuseNotImpl)160 TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
161   CheckNotImpl(FUSE_SETATTR);
162   CheckNotImpl(FUSE_READLINK);
163   CheckNotImpl(FUSE_SYMLINK);
164   CheckNotImpl(FUSE_MKNOD);
165   CheckNotImpl(FUSE_MKDIR);
166   CheckNotImpl(FUSE_UNLINK);
167   CheckNotImpl(FUSE_RMDIR);
168   CheckNotImpl(FUSE_RENAME);
169   CheckNotImpl(FUSE_LINK);
170   CheckNotImpl(FUSE_STATFS);
171   CheckNotImpl(FUSE_SETXATTR);
172   CheckNotImpl(FUSE_GETXATTR);
173   CheckNotImpl(FUSE_LISTXATTR);
174   CheckNotImpl(FUSE_REMOVEXATTR);
175   CheckNotImpl(FUSE_FLUSH);
176   CheckNotImpl(FUSE_OPENDIR);
177   CheckNotImpl(FUSE_READDIR);
178   CheckNotImpl(FUSE_RELEASEDIR);
179   CheckNotImpl(FUSE_FSYNCDIR);
180   CheckNotImpl(FUSE_GETLK);
181   CheckNotImpl(FUSE_SETLK);
182   CheckNotImpl(FUSE_SETLKW);
183   CheckNotImpl(FUSE_ACCESS);
184   CheckNotImpl(FUSE_CREATE);
185   CheckNotImpl(FUSE_INTERRUPT);
186   CheckNotImpl(FUSE_BMAP);
187   CheckNotImpl(FUSE_DESTROY);
188   CheckNotImpl(FUSE_IOCTL);
189   CheckNotImpl(FUSE_POLL);
190   CheckNotImpl(FUSE_NOTIFY_REPLY);
191   CheckNotImpl(FUSE_BATCH_FORGET);
192   CheckNotImpl(FUSE_FALLOCATE);
193   CheckNotImpl(FUSE_READDIRPLUS);
194   CheckNotImpl(FUSE_RENAME2);
195   CheckNotImpl(FUSE_LSEEK);
196 }
197 
TEST_F(FuseBridgeLoopTest,Proxy)198 TEST_F(FuseBridgeLoopTest, Proxy) {
199   CheckProxy(FUSE_LOOKUP);
200   CheckProxy(FUSE_GETATTR);
201   CheckProxy(FUSE_READ);
202   CheckProxy(FUSE_WRITE);
203   CheckProxy(FUSE_FSYNC);
204 
205   // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed.
206   CheckProxy(FUSE_OPEN);
207   CheckProxy(FUSE_RELEASE);
208 
209   // Ensure the loop exits.
210   Close();
211 }
212 
213 }  // namespace fuse
214 }  // namespace android
215