1 /*
2  * Copyright (c) 2022, Google, Inc. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <binder/IBinder.h>
25 #include <lib/binary_search_tree.h>
26 #include <lib/shared/binder_discover/binder_discover.h>
27 
28 #if defined(TRUSTY_USERSPACE)
29 #include <binder/RpcSession.h>
30 #include <binder/RpcTransportTipcTrusty.h>
31 #include <lib/tipc/tipc_srv.h>
32 #else
33 #include <kernel/mutex.h>
34 #endif
35 
36 struct DiscoveryTreeNode {
37     struct bst_node node;
38     std::string port;
39     android::sp<android::IBinder> binder;
40 
41     DiscoveryTreeNode() = delete;
DiscoveryTreeNodeDiscoveryTreeNode42     DiscoveryTreeNode(std::string&& port)
43             : node(BST_NODE_INITIAL_VALUE), port(std::move(port)) {}
DiscoveryTreeNodeDiscoveryTreeNode44     DiscoveryTreeNode(std::string&& port,
45                       const android::sp<android::IBinder>& ib)
46             : node(BST_NODE_INITIAL_VALUE), port(std::move(port)), binder(ib) {}
47 
compare_by_portDiscoveryTreeNode48     static int compare_by_port(struct bst_node* a, struct bst_node* b) {
49         auto nodea = containerof(a, DiscoveryTreeNode, node);
50         auto nodeb = containerof(b, DiscoveryTreeNode, node);
51         return nodea->port.compare(nodeb->port);
52     }
53 };
54 
55 static struct bst_root discovery_tree = BST_ROOT_INITIAL_VALUE;
56 
57 #if defined(TRUSTY_USERSPACE)
lock_discovery_tree(void)58 static inline void lock_discovery_tree(void) {}
unlock_discovery_tree(void)59 static inline void unlock_discovery_tree(void) {}
60 #else
61 static mutex_t discovery_tree_lock = MUTEX_INITIAL_VALUE(discovery_tree_lock);
62 
lock_discovery_tree(void)63 static inline void lock_discovery_tree(void) {
64     mutex_acquire(&discovery_tree_lock);
65 }
66 
unlock_discovery_tree(void)67 static inline void unlock_discovery_tree(void) {
68     mutex_release(&discovery_tree_lock);
69 }
70 #endif
71 
binder_discover_get_service(const char * port,android::sp<android::IBinder> & ib)72 int binder_discover_get_service(const char* port,
73                                 android::sp<android::IBinder>& ib) {
74     // Search the discovery tree to determine whether an in-process binder
75     // exists for this port; if found, return it.
76     DiscoveryTreeNode key{port};
77     lock_discovery_tree();
78     auto node = bst_search(&discovery_tree, &key.node,
79                            DiscoveryTreeNode::compare_by_port);
80     if (node != nullptr) {
81         ib = containerof(node, DiscoveryTreeNode, node)->binder;
82         unlock_discovery_tree();
83         return android::OK;
84     }
85     unlock_discovery_tree();
86 
87 #if defined(TRUSTY_USERSPACE)
88     android::sp<android::RpcSession> sess = android::RpcSession::make(
89             android::RpcTransportCtxFactoryTipcTrusty::make());
90     android::status_t status = sess->setupPreconnectedClient({}, [=]() {
91         int srv_fd = connect(port, IPC_CONNECT_WAIT_FOR_PORT);
92         return srv_fd >= 0 ? android::binder::unique_fd(srv_fd)
93                            : android::binder::unique_fd();
94     });
95     if (status != android::OK) {
96         return status;
97     }
98     ib = sess->getRootObject();
99 #else
100     panic("out-of-process services are currently unsupported in the kernel\n");
101 #endif
102     if (!ib) {
103         return android::BAD_VALUE;
104     }
105     return android::OK;
106 }
107 
binder_discover_add_service(const char * port,const android::sp<android::IBinder> & ib)108 int binder_discover_add_service(const char* port,
109                                 const android::sp<android::IBinder>& ib) {
110     auto node = new (std::nothrow) DiscoveryTreeNode{port, ib};
111     if (node == nullptr) {
112         return android::NO_MEMORY;
113     }
114 
115     lock_discovery_tree();
116     auto inserted = bst_insert(&discovery_tree, &node->node,
117                                DiscoveryTreeNode::compare_by_port);
118     unlock_discovery_tree();
119 
120     if (!inserted) {
121         delete node;
122         return android::ALREADY_EXISTS;
123     }
124 
125     return android::OK;
126 }
127 
binder_discover_remove_service(const char * port)128 int binder_discover_remove_service(const char* port) {
129     DiscoveryTreeNode key{port};
130     lock_discovery_tree();
131     auto node = bst_search(&discovery_tree, &key.node,
132                            DiscoveryTreeNode::compare_by_port);
133     if (node != nullptr) {
134         bst_delete(&discovery_tree, node);
135     }
136     unlock_discovery_tree();
137 
138     if (node == nullptr) {
139         return android::NAME_NOT_FOUND;
140     }
141 
142     // Destruct and free the underlying DiscoveryTreeNode
143     auto full_node = containerof(node, DiscoveryTreeNode, node);
144     delete full_node;
145 
146     return android::OK;
147 }
148