1 /*
2  * Copyright (C) 2013-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 
17 #include "client_tipc.h"
18 
19 #include <assert.h>
20 #include <errno.h>
21 #include <inttypes.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <interface/storage/storage.h>
29 #include <lib/tipc/tipc.h>
30 #include <openssl/mem.h>
31 #include <uapi/err.h>
32 
33 #include "block_device_tipc.h"
34 #include "client.h"
35 #include "client_session.h"
36 #include "client_session_tipc.h"
37 #include "ipc.h"
38 #include "session.h"
39 #include "storage_limits.h"
40 
41 /* macros to help manage debug output */
42 #define SS_ERR(args...) fprintf(stderr, "ss: " args)
43 #define SS_DBG_IO(args...) \
44     do {                   \
45     } while (0)
46 
47 #if 0
48 /* this can generate alot of spew on debug builds */
49 #define SS_INFO(args...) fprintf(stderr, "ss: " args)
50 #else
51 #define SS_INFO(args...) \
52     do {                 \
53     } while (0)
54 #endif
55 
56 static int client_handle_msg(struct ipc_channel_context* ctx,
57                              void* msg,
58                              size_t msg_size);
59 static void client_disconnect(struct ipc_channel_context* context);
60 static int send_response(struct storage_tipc_client_session* tipc_session,
61                          enum storage_err result,
62                          struct storage_msg* msg,
63                          void* out,
64                          size_t out_size);
65 static int send_result(struct storage_tipc_client_session* tipc_session,
66                        struct storage_msg* msg,
67                        enum storage_err result);
68 
extract_storage_op_flags(uint32_t msg_flags)69 static struct storage_op_flags extract_storage_op_flags(uint32_t msg_flags) {
70     return (struct storage_op_flags){
71             .allow_repaired = msg_flags & STORAGE_MSG_FLAG_FS_REPAIRED_ACK,
72             .complete_transaction =
73                     msg_flags & STORAGE_MSG_FLAG_TRANSACT_COMPLETE,
74             .update_checkpoint =
75                     msg_flags & STORAGE_MSG_FLAG_TRANSACT_CHECKPOINT,
76     };
77 }
78 
storage_tipc_file_delete(struct storage_client_session * session,struct storage_msg * msg,struct storage_file_delete_req * req,size_t req_size)79 static enum storage_err storage_tipc_file_delete(
80         struct storage_client_session* session,
81         struct storage_msg* msg,
82         struct storage_file_delete_req* req,
83         size_t req_size) {
84     if (req_size < sizeof(*req)) {
85         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
86         return STORAGE_ERR_NOT_VALID;
87     }
88 
89     if ((req->flags & ~STORAGE_FILE_DELETE_MASK) != 0) {
90         SS_ERR("%s: unexpected flags (0x%" PRIx32 ")\n", __func__, req->flags);
91         return STORAGE_ERR_NOT_VALID;
92     }
93 
94     return storage_file_delete(session, req->name, req_size - sizeof(*req),
95                                extract_storage_op_flags(msg->flags));
96 }
97 
storage_tipc_file_move(struct storage_client_session * session,struct storage_msg * msg,struct storage_file_move_req * req,size_t req_size)98 static enum storage_err storage_tipc_file_move(
99         struct storage_client_session* session,
100         struct storage_msg* msg,
101         struct storage_file_move_req* req,
102         size_t req_size) {
103     if (req_size < sizeof(*req)) {
104         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
105         return STORAGE_ERR_NOT_VALID;
106     }
107 
108     if ((req->flags & ~STORAGE_FILE_MOVE_MASK) != 0) {
109         SS_ERR("invalid move flags 0x%" PRIx32 "\n", req->flags);
110         return STORAGE_ERR_NOT_VALID;
111     }
112 
113     size_t names_combined_len = req_size - sizeof(*req);
114     size_t src_len = req->old_name_len;
115     if (src_len >= names_combined_len) {
116         SS_ERR("%s: invalid src filename length %zu >= %zu\n", __func__,
117                src_len, names_combined_len);
118         return STORAGE_ERR_NOT_VALID;
119     }
120 
121     enum file_create_mode file_create_mode;
122     if (req->flags & STORAGE_FILE_MOVE_CREATE) {
123         file_create_mode = req->flags & STORAGE_FILE_MOVE_CREATE_EXCLUSIVE
124                                    ? FILE_OPEN_CREATE_EXCLUSIVE
125                                    : FILE_OPEN_CREATE;
126     } else {
127         file_create_mode = FILE_OPEN_NO_CREATE;
128     }
129 
130     return storage_file_move(
131             session, req->handle, req->flags & STORAGE_FILE_MOVE_OPEN_FILE,
132             req->old_new_name, src_len, req->old_new_name + src_len,
133             names_combined_len - src_len, file_create_mode,
134             extract_storage_op_flags(msg->flags));
135 }
136 
storage_tipc_file_open(struct storage_tipc_client_session * tipc_session,struct storage_msg * msg,struct storage_file_open_req * req,size_t req_size)137 static enum storage_err storage_tipc_file_open(
138         struct storage_tipc_client_session* tipc_session,
139         struct storage_msg* msg,
140         struct storage_file_open_req* req,
141         size_t req_size) {
142     if (req_size < sizeof(*req)) {
143         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
144         return send_result(tipc_session, msg, STORAGE_ERR_NOT_VALID);
145     }
146 
147     if ((req->flags & ~STORAGE_FILE_OPEN_MASK) != 0) {
148         SS_ERR("%s: invalid flags 0x%" PRIx32 "\n", __func__, req->flags);
149         return send_result(tipc_session, msg, STORAGE_ERR_NOT_VALID);
150     }
151 
152     enum file_create_mode file_create_mode;
153     if (req->flags & STORAGE_FILE_OPEN_CREATE) {
154         file_create_mode = req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE
155                                    ? FILE_OPEN_CREATE_EXCLUSIVE
156                                    : FILE_OPEN_CREATE;
157     } else {
158         file_create_mode = FILE_OPEN_NO_CREATE;
159     }
160 
161     struct storage_file_open_resp resp;
162     enum storage_err result = storage_file_open(
163             &tipc_session->session, req->name, req_size - sizeof(*req),
164             file_create_mode, req->flags & STORAGE_FILE_OPEN_TRUNCATE,
165             extract_storage_op_flags(msg->flags), &resp.handle);
166     if (result != STORAGE_NO_ERROR) {
167         return send_result(tipc_session, msg, result);
168     }
169     return send_response(tipc_session, result, msg, &resp, sizeof(resp));
170 }
171 
storage_tipc_file_close(struct storage_client_session * session,struct storage_msg * msg,struct storage_file_close_req * req,size_t req_size)172 static enum storage_err storage_tipc_file_close(
173         struct storage_client_session* session,
174         struct storage_msg* msg,
175         struct storage_file_close_req* req,
176         size_t req_size) {
177     if (req_size != sizeof(*req)) {
178         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
179         return STORAGE_ERR_NOT_VALID;
180     }
181     return storage_file_close(session, req->handle,
182                               extract_storage_op_flags(msg->flags));
183 }
184 
storage_tipc_file_write(struct storage_client_session * session,struct storage_msg * msg,struct storage_file_write_req * req,size_t req_size)185 static enum storage_err storage_tipc_file_write(
186         struct storage_client_session* session,
187         struct storage_msg* msg,
188         struct storage_file_write_req* req,
189         size_t req_size) {
190     if (req_size <= sizeof(*req)) {
191         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
192         return STORAGE_ERR_NOT_VALID;
193     }
194     return storage_file_write(session, req->handle, req->offset, req->data,
195                               req_size - sizeof(*req),
196                               extract_storage_op_flags(msg->flags));
197 }
198 
storage_tipc_file_read(struct storage_tipc_client_session * tipc_session,struct storage_msg * msg,struct storage_file_read_req * req,size_t req_size)199 static enum storage_err storage_tipc_file_read(
200         struct storage_tipc_client_session* tipc_session,
201         struct storage_msg* msg,
202         struct storage_file_read_req* req,
203         size_t req_size) {
204     if (req_size != sizeof(*req)) {
205         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
206         return send_result(tipc_session, msg, STORAGE_ERR_NOT_VALID);
207     }
208 
209     /*
210      * After getting the args out of req, we still need `*msg`, but won't need
211      * the rest of the buffer anymore. We can reuse that space to hold the
212      * response.
213      */
214     uint8_t* resp = (uint8_t*)(msg + 1);
215     size_t resp_len = STORAGE_MAX_BUFFER_SIZE - sizeof(*msg);
216 
217     enum storage_err result = storage_file_read(
218             &tipc_session->session, req->handle, req->size, req->offset,
219             extract_storage_op_flags(msg->flags), resp, &resp_len);
220     if (result != STORAGE_NO_ERROR) {
221         return send_result(tipc_session, msg, result);
222     }
223     return send_response(tipc_session, result, msg, resp, resp_len);
224 }
225 
226 struct storage_tipc_file_iter_data {
227     char resp_buf[1024];
228     size_t buf_used;
229 };
230 
buf_has_space(void * self,size_t max_path_len)231 static bool buf_has_space(void* self, size_t max_path_len) {
232     struct storage_tipc_file_iter_data* this = self;
233     /* One extra byte for flags plus one for the path's nul terminator */
234     size_t max_resp_size = max_path_len + 2;
235     return this->buf_used + max_resp_size <= sizeof(this->resp_buf);
236 }
237 
write_to_buf(void * self,enum storage_file_list_flag flags,const char * path,size_t path_len)238 static void write_to_buf(void* self,
239                          enum storage_file_list_flag flags,
240                          const char* path,
241                          size_t path_len) {
242     struct storage_tipc_file_iter_data* this = self;
243     struct storage_file_list_resp* resp =
244             (void*)(this->resp_buf + this->buf_used);
245 
246     resp->flags = flags;
247     this->buf_used++;
248 
249     if (path) {
250         strncpy(resp->name, path, path_len);
251         resp->name[path_len] = '\0';
252         this->buf_used += path_len + 1;
253     }
254 }
255 
storage_tipc_file_list(struct storage_tipc_client_session * tipc_session,struct storage_msg * msg,struct storage_file_list_req * req,size_t req_size)256 static enum storage_err storage_tipc_file_list(
257         struct storage_tipc_client_session* tipc_session,
258         struct storage_msg* msg,
259         struct storage_file_list_req* req,
260         size_t req_size) {
261     if (req_size < sizeof(*req)) {
262         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
263         return send_result(tipc_session, msg, STORAGE_ERR_NOT_VALID);
264     }
265 
266     struct storage_tipc_file_iter_data callback_data = {
267             .buf_used = 0,
268     };
269 
270     enum storage_err result = storage_file_list(
271             &tipc_session->session, req->max_count,
272             req->flags & STORAGE_FILE_LIST_STATE_MASK, req->name,
273             req_size - sizeof(*req), extract_storage_op_flags(msg->flags),
274             buf_has_space, write_to_buf, &callback_data);
275     if (result != STORAGE_NO_ERROR) {
276         return send_result(tipc_session, msg, result);
277     }
278     return send_response(tipc_session, result, msg, callback_data.resp_buf,
279                          callback_data.buf_used);
280 }
281 
storage_tipc_file_get_size(struct storage_tipc_client_session * tipc_session,struct storage_msg * msg,struct storage_file_get_size_req * req,size_t req_size)282 static enum storage_err storage_tipc_file_get_size(
283         struct storage_tipc_client_session* tipc_session,
284         struct storage_msg* msg,
285         struct storage_file_get_size_req* req,
286         size_t req_size) {
287     if (req_size != sizeof(*req)) {
288         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
289         return send_result(tipc_session, msg, STORAGE_ERR_NOT_VALID);
290     }
291 
292     struct storage_file_get_size_resp resp;
293     enum storage_err result = storage_file_get_size(
294             &tipc_session->session, req->handle,
295             extract_storage_op_flags(msg->flags), &resp.size);
296     if (result != STORAGE_NO_ERROR) {
297         return send_result(tipc_session, msg, result);
298     }
299     return send_response(tipc_session, result, msg, &resp, sizeof(resp));
300 }
301 
storage_tipc_file_set_size(struct storage_client_session * session,struct storage_msg * msg,struct storage_file_set_size_req * req,size_t req_size)302 static enum storage_err storage_tipc_file_set_size(
303         struct storage_client_session* session,
304         struct storage_msg* msg,
305         struct storage_file_set_size_req* req,
306         size_t req_size) {
307     if (req_size != sizeof(*req)) {
308         SS_ERR("%s: invalid request size (%zu)\n", __func__, req_size);
309         return STORAGE_ERR_NOT_VALID;
310     }
311     return storage_file_set_size(session, req->handle, req->size,
312                                  extract_storage_op_flags(msg->flags));
313 }
314 
chan_context_to_client_session(struct ipc_channel_context * ctx)315 static struct storage_tipc_client_session* chan_context_to_client_session(
316         struct ipc_channel_context* ctx) {
317     assert(ctx != NULL);
318     struct storage_tipc_client_session* tipc_session;
319 
320     tipc_session =
321             containerof(ctx, struct storage_tipc_client_session, chan_ctx);
322     assert(tipc_session->session.magic == STORAGE_CLIENT_SESSION_MAGIC);
323     return tipc_session;
324 }
325 
port_context_to_client_port_context(struct ipc_port_context * context)326 static struct client_port_context* port_context_to_client_port_context(
327         struct ipc_port_context* context) {
328     assert(context != NULL);
329 
330     return containerof(context, struct client_port_context, client_ctx);
331 }
332 
client_channel_ops_init(struct ipc_channel_ops * ops)333 static void client_channel_ops_init(struct ipc_channel_ops* ops) {
334     ops->on_handle_msg = client_handle_msg;
335     ops->on_disconnect = client_disconnect;
336 }
337 
client_connect(struct ipc_port_context * parent_ctx,const uuid_t * peer_uuid,handle_t chan_handle)338 static struct ipc_channel_context* client_connect(
339         struct ipc_port_context* parent_ctx,
340         const uuid_t* peer_uuid,
341         handle_t chan_handle) {
342     struct client_port_context* client_port_context;
343     struct storage_tipc_client_session* client_tipc_session;
344 
345     client_port_context = port_context_to_client_port_context(parent_ctx);
346 
347     client_tipc_session = calloc(1, sizeof(*client_tipc_session));
348     if (client_tipc_session == NULL) {
349         SS_ERR("out of memory allocating client session\n");
350         return NULL;
351     }
352 
353     struct storage_client_session* client_session =
354             &client_tipc_session->session;
355     storage_client_session_init(client_session, client_port_context->tr_state,
356                                 peer_uuid);
357 
358     client_channel_ops_init(&client_tipc_session->chan_ctx.ops);
359     return &client_tipc_session->chan_ctx;
360 }
361 
client_disconnect(struct ipc_channel_context * context)362 static void client_disconnect(struct ipc_channel_context* context) {
363     struct storage_tipc_client_session* tipc_session =
364             chan_context_to_client_session(context);
365 
366     storage_client_session_destroy(&tipc_session->session);
367     OPENSSL_cleanse(tipc_session, sizeof(struct storage_tipc_client_session));
368     free(tipc_session);
369 }
370 
send_response(struct storage_tipc_client_session * tipc_session,enum storage_err result,struct storage_msg * msg,void * out,size_t out_size)371 static int send_response(struct storage_tipc_client_session* tipc_session,
372                          enum storage_err result,
373                          struct storage_msg* msg,
374                          void* out,
375                          size_t out_size) {
376     size_t resp_buf_count = 1;
377     if (result == STORAGE_NO_ERROR && out != NULL && out_size != 0) {
378         ++resp_buf_count;
379     }
380 
381     struct iovec resp_bufs[2];
382 
383     msg->cmd |= STORAGE_RESP_BIT;
384     msg->flags = 0;
385     msg->size = sizeof(struct storage_msg) + out_size;
386     msg->result = result;
387 
388     resp_bufs[0].iov_base = msg;
389     resp_bufs[0].iov_len = sizeof(struct storage_msg);
390 
391     if (resp_buf_count == 2) {
392         resp_bufs[1].iov_base = out;
393         resp_bufs[1].iov_len = out_size;
394     }
395 
396     struct ipc_msg resp_ipc_msg = {
397             .iov = resp_bufs,
398             .num_iov = resp_buf_count,
399     };
400 
401     return send_msg(tipc_session->chan_ctx.common.handle, &resp_ipc_msg);
402 }
403 
send_result(struct storage_tipc_client_session * tipc_session,struct storage_msg * msg,enum storage_err result)404 static int send_result(struct storage_tipc_client_session* tipc_session,
405                        struct storage_msg* msg,
406                        enum storage_err result) {
407     return send_response(tipc_session, result, msg, NULL, 0);
408 }
409 
client_handle_msg(struct ipc_channel_context * ctx,void * msg_buf,size_t msg_size)410 static int client_handle_msg(struct ipc_channel_context* ctx,
411                              void* msg_buf,
412                              size_t msg_size) {
413     struct storage_tipc_client_session* tipc_session;
414     struct storage_client_session* session;
415     struct storage_msg* msg = msg_buf;
416     size_t payload_len;
417     enum storage_err result;
418     void* payload;
419 
420     tipc_session = chan_context_to_client_session(ctx);
421     session = &tipc_session->session;
422 
423     if (msg_size < sizeof(struct storage_msg)) {
424         SS_ERR("%s: invalid message of size (%zu)\n", __func__, msg_size);
425         struct storage_msg err_msg = {.cmd = STORAGE_RESP_MSG_ERR};
426         send_result(tipc_session, &err_msg, STORAGE_ERR_NOT_VALID);
427         return ERR_NOT_VALID; /* would force to close connection */
428     }
429 
430     payload_len = msg_size - sizeof(struct storage_msg);
431     payload = msg->payload;
432 
433     switch (msg->cmd) {
434     case STORAGE_FILE_DELETE:
435         result = storage_tipc_file_delete(session, msg, payload, payload_len);
436         break;
437     case STORAGE_FILE_MOVE:
438         result = storage_tipc_file_move(session, msg, payload, payload_len);
439         break;
440     case STORAGE_FILE_OPEN:
441         return storage_tipc_file_open(tipc_session, msg, payload, payload_len);
442     case STORAGE_FILE_CLOSE:
443         result = storage_tipc_file_close(session, msg, payload, payload_len);
444         break;
445     case STORAGE_FILE_WRITE:
446         result = storage_tipc_file_write(session, msg, payload, payload_len);
447         break;
448     case STORAGE_FILE_READ:
449         return storage_tipc_file_read(tipc_session, msg, payload, payload_len);
450     case STORAGE_FILE_LIST:
451         return storage_tipc_file_list(tipc_session, msg, payload, payload_len);
452     case STORAGE_FILE_GET_SIZE:
453         return storage_tipc_file_get_size(tipc_session, msg, payload,
454                                           payload_len);
455     case STORAGE_FILE_SET_SIZE:
456         result = storage_tipc_file_set_size(session, msg, payload, payload_len);
457         break;
458     case STORAGE_END_TRANSACTION:
459         result = storage_transaction_end(session,
460                                          extract_storage_op_flags(msg->flags));
461         break;
462     default:
463         SS_ERR("%s: unsupported command 0x%" PRIx32 "\n", __func__, msg->cmd);
464         result = STORAGE_ERR_UNIMPLEMENTED;
465         break;
466     }
467 
468     return send_result(tipc_session, msg, result);
469 }
470 
client_create_port(struct tipc_hset * hset,struct ipc_port_context * client_ctx,const char * port_name)471 int client_create_port(struct tipc_hset* hset,
472                        struct ipc_port_context* client_ctx,
473                        const char* port_name) {
474     int ret;
475     uint32_t flags = IPC_PORT_ALLOW_TA_CONNECT;
476 #if TEST_BUILD
477     flags |= IPC_PORT_ALLOW_NS_CONNECT;
478 #endif
479 
480     /* start accepting client connections */
481     client_ctx->ops.on_connect = client_connect;
482     ret = ipc_port_create(hset, client_ctx, port_name, 1,
483                           STORAGE_MAX_BUFFER_SIZE, flags);
484     if (ret < 0) {
485         SS_ERR("%s: failure initializing client port (%d)\n", __func__, ret);
486         return ret;
487     }
488     return 0;
489 }
490