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