1 /*
2  * Copyright (C) 2015-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 "block_device_tipc.h"
18 
19 #include <errno.h>
20 #include <inttypes.h>
21 #include <stdint.h>
22 #include <string.h>
23 
24 #include <lib/system_state/system_state.h>
25 #include <lib/tipc/tipc.h>
26 #include <lk/compiler.h>
27 #include <trusty_ipc.h>
28 #include <uapi/err.h>
29 
30 #include <interface/storage/storage.h>
31 
32 #include <openssl/mem.h>
33 #include <openssl/rand.h>
34 
35 #include "block_cache.h"
36 #include "client_tipc.h"
37 #include "fs.h"
38 #include "ipc.h"
39 #include "rpmb.h"
40 #include "tipc_ns.h"
41 
42 #ifdef APP_STORAGE_RPMB_BLOCK_SIZE
43 #define BLOCK_SIZE_RPMB (APP_STORAGE_RPMB_BLOCK_SIZE)
44 #else
45 #define BLOCK_SIZE_RPMB (512)
46 #endif
47 #ifdef APP_STORAGE_RPMB_BLOCK_COUNT
48 #define BLOCK_COUNT_RPMB (APP_STORAGE_RPMB_BLOCK_COUNT)
49 #else
50 #define BLOCK_COUNT_RPMB (0) /* Auto detect */
51 #endif
52 #ifdef APP_STORAGE_MAIN_BLOCK_SIZE
53 #define BLOCK_SIZE_MAIN (APP_STORAGE_MAIN_BLOCK_SIZE)
54 #else
55 #define BLOCK_SIZE_MAIN (2048)
56 #endif
57 
58 /*
59  * This is here in case we're using an old storageproxyd that does not have
60  * support for STORAGE_FILE_GET_MAX_SIZE
61  */
62 #ifdef APP_STORAGE_MAIN_BLOCK_COUNT
63 #define BLOCK_COUNT_MAIN (APP_STORAGE_MAIN_BLOCK_COUNT)
64 #else
65 #define BLOCK_COUNT_MAIN (0x10000000000 / BLOCK_SIZE_MAIN)
66 #endif
67 
68 #define BLOCK_SIZE_RPMB_BLOCKS (BLOCK_SIZE_RPMB / RPMB_BUF_SIZE)
69 
70 STATIC_ASSERT(BLOCK_SIZE_RPMB_BLOCKS == 1 || BLOCK_SIZE_RPMB_BLOCKS == 2);
71 STATIC_ASSERT((BLOCK_SIZE_RPMB_BLOCKS * RPMB_BUF_SIZE) == BLOCK_SIZE_RPMB);
72 
73 STATIC_ASSERT(BLOCK_COUNT_RPMB == 0 || BLOCK_COUNT_RPMB >= 8);
74 
75 STATIC_ASSERT(BLOCK_SIZE_MAIN >= 256);
76 STATIC_ASSERT(BLOCK_COUNT_MAIN >= 8);
77 STATIC_ASSERT(BLOCK_SIZE_MAIN >= BLOCK_SIZE_RPMB);
78 
79 /* Ensure that we can fit a superblock + backup in an RPMB block */
80 STATIC_ASSERT(BLOCK_SIZE_RPMB >= 256);
81 
82 #define SS_ERR(args...) fprintf(stderr, "ss: " args)
83 #define SS_WARN(args...) fprintf(stderr, "ss: " args)
84 
85 #ifdef SS_DATA_DEBUG_IO
86 #define SS_DBG_IO(args...) fprintf(stdout, "ss: " args)
87 #else
88 #define SS_DBG_IO(args...) \
89     do {                   \
90     } while (0)
91 #endif
92 
93 const char file_system_id_td[] = "td";
94 const char file_system_id_tdea[] = "tdea";
95 const char file_system_id_tdp[] = "tdp";
96 const char file_system_id_tp[] = "tp";
97 const char file_system_id_nsp[] = "nsp";
98 
99 const char ns_filename[] = "0";
100 const char ns_alternate_filename[] = "alternate/0";
101 const char tdp_filename[] = "persist/0";
102 const char nsp_filename[] = "persist/nsp";
103 
104 struct rpmb_key_derivation_in {
105     uint8_t prefix[sizeof(struct key)];
106     uint8_t block_data[RPMB_BUF_SIZE];
107 };
108 
109 struct rpmb_key_derivation_out {
110     struct rpmb_key rpmb_key;
111     uint8_t unused[sizeof(struct key)];
112 };
113 
114 struct rpmb_span {
115     uint16_t start;
116     uint16_t block_count;
117 };
118 
119 struct rpmb_spans {
120     struct rpmb_span key;
121     struct rpmb_span ns;
122     struct rpmb_span tdp;
123     /* Start of the rest of the RPMB, which is used for TP and TDEA */
124     uint16_t rpmb_start;
125 };
126 
rpmb_check(struct rpmb_state * rpmb_state,uint16_t block)127 static int rpmb_check(struct rpmb_state* rpmb_state, uint16_t block) {
128     int ret;
129     uint8_t tmp[RPMB_BUF_SIZE];
130     ret = rpmb_read(rpmb_state, tmp, block, 1);
131     SS_DBG_IO("%s: check rpmb_block %d, ret %d\n", __func__, block, ret);
132     return ret;
133 }
134 
rpmb_search_size(struct rpmb_state * rpmb_state,uint16_t hint)135 static uint32_t rpmb_search_size(struct rpmb_state* rpmb_state, uint16_t hint) {
136     int ret;
137     uint32_t low = 0;
138     uint16_t high = UINT16_MAX;
139     uint16_t curr = hint ? hint - 1 : UINT16_MAX;
140 
141     while (low <= high) {
142         ret = rpmb_check(rpmb_state, curr);
143         switch (ret) {
144         case 0:
145             low = curr + 1;
146             break;
147         case -ENOENT:
148             high = curr - 1;
149             break;
150         default:
151             return 0;
152         };
153         if (ret || curr != hint) {
154             curr = (low + high) / 2;
155             hint = curr;
156         } else {
157             curr = curr + 1;
158         }
159     }
160     assert((uint32_t)high + 1 == low);
161     return low;
162 }
163 
dev_rpmb_to_state(struct block_device * dev)164 static struct block_device_rpmb* dev_rpmb_to_state(struct block_device* dev) {
165     assert(dev);
166     return containerof(dev, struct block_device_rpmb, dev);
167 }
168 
block_device_tipc_rpmb_start_read(struct block_device * dev,data_block_t block)169 static void block_device_tipc_rpmb_start_read(struct block_device* dev,
170                                               data_block_t block) {
171     int ret;
172     uint8_t tmp[BLOCK_SIZE_RPMB]; /* TODO: pass data in? */
173     uint16_t rpmb_block;
174     struct block_device_rpmb* dev_rpmb = dev_rpmb_to_state(dev);
175 
176     assert(block < dev->block_count);
177     rpmb_block = block + dev_rpmb->base;
178 
179     ret = rpmb_read(dev_rpmb->rpmb_state, tmp,
180                     rpmb_block * BLOCK_SIZE_RPMB_BLOCKS,
181                     BLOCK_SIZE_RPMB_BLOCKS);
182 
183     SS_DBG_IO("%s: block %" PRIu64 ", base %d, rpmb_block %d, ret %d\n",
184               __func__, block, dev_rpmb->base, rpmb_block, ret);
185 
186     block_cache_complete_read(dev, block, tmp, BLOCK_SIZE_RPMB,
187                               ret ? BLOCK_READ_IO_ERROR : BLOCK_READ_SUCCESS);
188 }
189 
translate_write_error(int rc)190 static inline enum block_write_error translate_write_error(int rc) {
191     switch (rc) {
192     case 0:
193         return BLOCK_WRITE_SUCCESS;
194     case -EUCLEAN:
195         return BLOCK_WRITE_FAILED_UNKNOWN_STATE;
196     case ERR_IO:
197         return BLOCK_WRITE_SYNC_FAILED;
198     default:
199         return BLOCK_WRITE_FAILED;
200     }
201 }
202 
block_device_tipc_rpmb_start_write(struct block_device * dev,data_block_t block,const void * data,size_t data_size,bool sync)203 static void block_device_tipc_rpmb_start_write(struct block_device* dev,
204                                                data_block_t block,
205                                                const void* data,
206                                                size_t data_size,
207                                                bool sync) {
208     int ret;
209     uint16_t rpmb_block;
210     struct block_device_rpmb* dev_rpmb = dev_rpmb_to_state(dev);
211 
212     /* We currently sync every rpmb write. TODO: can we avoid this? */
213     (void)sync;
214 
215     assert(data_size == BLOCK_SIZE_RPMB);
216     assert(block < dev->block_count);
217 
218     rpmb_block = block + dev_rpmb->base;
219 
220     ret = rpmb_write(dev_rpmb->rpmb_state, data,
221                      rpmb_block * BLOCK_SIZE_RPMB_BLOCKS,
222                      BLOCK_SIZE_RPMB_BLOCKS, true, dev_rpmb->is_userdata);
223 
224     SS_DBG_IO("%s: block %" PRIu64 ", base %d, rpmb_block %d, ret %d\n",
225               __func__, block, dev_rpmb->base, rpmb_block, ret);
226 
227     block_cache_complete_write(dev, block, translate_write_error(ret));
228 }
229 
block_device_tipc_rpmb_wait_for_io(struct block_device * dev)230 static void block_device_tipc_rpmb_wait_for_io(struct block_device* dev) {
231     assert(0); /* TODO: use async read/write */
232 }
233 
to_block_device_ns(struct block_device * dev)234 static struct block_device_ns* to_block_device_ns(struct block_device* dev) {
235     assert(dev);
236     return containerof(dev, struct block_device_ns, dev);
237 }
238 
block_device_tipc_ns_start_read(struct block_device * dev,data_block_t block)239 static void block_device_tipc_ns_start_read(struct block_device* dev,
240                                             data_block_t block) {
241     int ret;
242     enum block_read_error res;
243     uint8_t tmp[BLOCK_SIZE_MAIN]; /* TODO: pass data in? */
244     struct block_device_ns* dev_ns = to_block_device_ns(dev);
245 
246     ret = ns_read_pos(dev_ns->ipc_handle, dev_ns->ns_handle,
247                       block * BLOCK_SIZE_MAIN, tmp, BLOCK_SIZE_MAIN);
248     SS_DBG_IO("%s: block %" PRIu64 ", ret %d\n", __func__, block, ret);
249     if (ret == 0) {
250         res = BLOCK_READ_NO_DATA;
251     } else if (ret == BLOCK_SIZE_MAIN) {
252         res = BLOCK_READ_SUCCESS;
253     } else {
254         res = BLOCK_READ_IO_ERROR;
255     }
256     block_cache_complete_read(dev, block, tmp, BLOCK_SIZE_MAIN, res);
257 }
258 
block_device_tipc_ns_start_write(struct block_device * dev,data_block_t block,const void * data,size_t data_size,bool sync)259 static void block_device_tipc_ns_start_write(struct block_device* dev,
260                                              data_block_t block,
261                                              const void* data,
262                                              size_t data_size,
263                                              bool sync) {
264     int ret;
265     enum block_write_error res = BLOCK_WRITE_FAILED;
266     struct block_device_ns* dev_ns = to_block_device_ns(dev);
267 
268     assert(data_size == BLOCK_SIZE_MAIN);
269 
270     ret = ns_write_pos(dev_ns->ipc_handle, dev_ns->ns_handle,
271                        block * BLOCK_SIZE_MAIN, data, data_size,
272                        dev_ns->is_userdata, sync);
273     SS_DBG_IO("%s: block %" PRIu64 ", ret %d\n", __func__, block, ret);
274     if (ret == BLOCK_SIZE_MAIN) {
275         res = BLOCK_WRITE_SUCCESS;
276     } else if (ret < 0) {
277         res = translate_write_error(ret);
278     }
279     block_cache_complete_write(dev, block, res);
280 }
281 
block_device_tipc_ns_wait_for_io(struct block_device * dev)282 static void block_device_tipc_ns_wait_for_io(struct block_device* dev) {
283     assert(0); /* TODO: use async read/write */
284 }
285 
block_device_tipc_init_dev_rpmb(struct block_device_rpmb * dev_rpmb,struct rpmb_state * rpmb_state,uint16_t base,uint32_t block_count,bool is_userdata)286 static void block_device_tipc_init_dev_rpmb(struct block_device_rpmb* dev_rpmb,
287                                             struct rpmb_state* rpmb_state,
288                                             uint16_t base,
289                                             uint32_t block_count,
290                                             bool is_userdata) {
291     dev_rpmb->dev.start_read = block_device_tipc_rpmb_start_read;
292     dev_rpmb->dev.start_write = block_device_tipc_rpmb_start_write;
293     dev_rpmb->dev.wait_for_io = block_device_tipc_rpmb_wait_for_io;
294     dev_rpmb->dev.block_count = block_count;
295     dev_rpmb->dev.block_size = BLOCK_SIZE_RPMB;
296     dev_rpmb->dev.block_num_size = 2;
297     dev_rpmb->dev.mac_size = 2;
298     dev_rpmb->dev.tamper_detecting = true;
299     list_initialize(&dev_rpmb->dev.io_ops);
300     dev_rpmb->rpmb_state = rpmb_state;
301     dev_rpmb->base = base;
302     dev_rpmb->is_userdata = is_userdata;
303 }
304 
block_device_tipc_init_dev_ns(struct block_device_ns * dev_ns,handle_t ipc_handle,bool is_userdata)305 static void block_device_tipc_init_dev_ns(struct block_device_ns* dev_ns,
306                                           handle_t ipc_handle,
307                                           bool is_userdata) {
308     dev_ns->dev.start_read = block_device_tipc_ns_start_read;
309     dev_ns->dev.start_write = block_device_tipc_ns_start_write;
310     dev_ns->dev.wait_for_io = block_device_tipc_ns_wait_for_io;
311     dev_ns->dev.block_size = BLOCK_SIZE_MAIN;
312     dev_ns->dev.block_num_size = sizeof(data_block_t);
313     dev_ns->dev.mac_size = sizeof(struct mac);
314     dev_ns->dev.tamper_detecting = false;
315     list_initialize(&dev_ns->dev.io_ops);
316     dev_ns->ipc_handle = ipc_handle;
317     dev_ns->ns_handle = 0; /* Filled in later */
318     dev_ns->is_userdata = is_userdata;
319 }
320 
321 /**
322  * hwkey_derive_rpmb_key() - Derive rpmb key through hwkey server.
323  * @session:  The hwkey session handle.
324  * @in:       The input data to derive rpmb key.
325  * @out:      The output data from deriving rpmb key.
326  *
327  * Return: NO_ERROR on success, error code less than 0 on error.
328  */
hwkey_derive_rpmb_key(hwkey_session_t session,const struct rpmb_key_derivation_in * in,struct rpmb_key_derivation_out * out)329 static int hwkey_derive_rpmb_key(hwkey_session_t session,
330                                  const struct rpmb_key_derivation_in* in,
331                                  struct rpmb_key_derivation_out* out) {
332     uint32_t kdf_version = HWKEY_KDF_VERSION_1;
333     const void* in_buf = in;
334     void* out_buf = out;
335     uint32_t key_size = sizeof(*out);
336     STATIC_ASSERT(sizeof(*in) >= sizeof(*out));
337 
338     int ret = hwkey_derive(session, &kdf_version, in_buf, out_buf, key_size);
339     if (ret < 0) {
340         SS_ERR("%s: failed to get key: %d\n", __func__, ret);
341         return ret;
342     }
343 
344     return NO_ERROR;
345 }
346 
347 /**
348  * block_device_tipc_program_key() - Program a rpmb key derived through hwkey
349  * server.
350  * @state:              The rpmb state.
351  * @rpmb_key_part_base: The base of rpmb_key_part in rpmb partition.
352  * @in                  The input rpmb key derivation data.
353  * @out                 The output rpmb key derivation data.
354  * @hwkey_session:      The hwkey session handle.
355  *
356  * Return: NO_ERROR on success, error code less than 0 on error.
357  */
block_device_tipc_program_key(struct rpmb_state * state,uint16_t rpmb_key_part_base,struct rpmb_key_derivation_in * in,struct rpmb_key_derivation_out * out,hwkey_session_t hwkey_session)358 static int block_device_tipc_program_key(struct rpmb_state* state,
359                                          uint16_t rpmb_key_part_base,
360                                          struct rpmb_key_derivation_in* in,
361                                          struct rpmb_key_derivation_out* out,
362                                          hwkey_session_t hwkey_session) {
363     int ret;
364 
365     if (!system_state_provisioning_allowed()) {
366         ret = ERR_NOT_ALLOWED;
367         SS_ERR("%s: rpmb key provisioning is not allowed (%d)\n", __func__,
368                ret);
369         return ret;
370     }
371 
372     STATIC_ASSERT(sizeof(in->block_data) >= sizeof(out->rpmb_key));
373     RAND_bytes(in->block_data, sizeof(out->rpmb_key.byte));
374     ret = hwkey_derive_rpmb_key(hwkey_session, in, out);
375     if (ret < 0) {
376         SS_ERR("%s: hwkey_derive_rpmb_key failed (%d)\n", __func__, ret);
377         return ret;
378     }
379 
380     ret = rpmb_program_key(state, &out->rpmb_key);
381     if (ret < 0) {
382         SS_ERR("%s: rpmb_program_key failed (%d)\n", __func__, ret);
383         return ret;
384     }
385 
386     rpmb_set_key(state, &out->rpmb_key);
387 
388     ret = rpmb_write(state, in->block_data,
389                      rpmb_key_part_base * BLOCK_SIZE_RPMB_BLOCKS, 1, false,
390                      false);
391     if (ret < 0) {
392         SS_ERR("%s: rpmb_write failed (%d)\n", __func__, ret);
393         return ret;
394     }
395 
396     return 0;
397 }
398 
block_device_tipc_derive_rpmb_key(struct rpmb_state * state,uint16_t rpmb_key_part_base,hwkey_session_t hwkey_session)399 static int block_device_tipc_derive_rpmb_key(struct rpmb_state* state,
400                                              uint16_t rpmb_key_part_base,
401                                              hwkey_session_t hwkey_session) {
402     int ret;
403     struct rpmb_key_derivation_in in = {
404             .prefix = {
405                     0x74, 0x68, 0x43, 0x49, 0x2b, 0xa2, 0x4f, 0x77,
406                     0xb0, 0x8e, 0xd1, 0xd4, 0xb7, 0x01, 0x0e, 0xc6,
407                     0x86, 0x4c, 0xa9, 0xe5, 0x28, 0xf0, 0x20, 0xb1,
408                     0xb8, 0x1e, 0x73, 0x3d, 0x8c, 0x9d, 0xb9, 0x96,
409             }};
410     struct rpmb_key_derivation_out out;
411 
412     ret = rpmb_read_no_mac(state, in.block_data,
413                            rpmb_key_part_base * BLOCK_SIZE_RPMB_BLOCKS, 1);
414 
415     if (ret < 0) {
416         ret = block_device_tipc_program_key(state, rpmb_key_part_base, &in,
417                                             &out, hwkey_session);
418         if (ret < 0) {
419             SS_ERR("%s: program_key failed (%d)\n", __func__, ret);
420             return ret;
421         }
422 
423         return 0;
424     }
425 
426     ret = hwkey_derive_rpmb_key(hwkey_session, &in, &out);
427     if (ret < 0) {
428         SS_ERR("%s: hwkey_derive_rpmb_key failed (%d)\n", __func__, ret);
429         return ret;
430     }
431 
432     rpmb_set_key(state, &out.rpmb_key);
433 
434     /*
435      * Validate that the derived rpmb key is correct as we use it to check
436      * both mac and content of the block_data.
437      */
438     ret = rpmb_verify(state, in.block_data,
439                       rpmb_key_part_base * BLOCK_SIZE_RPMB_BLOCKS, 1);
440     if (ret < 0) {
441         SS_ERR("%s: rpmb_verify failed with the derived rpmb key (%d)\n",
442                __func__, ret);
443         return ret;
444     }
445 
446     return 0;
447 }
448 
block_device_tipc_init_rpmb_key(struct rpmb_state * state,const struct rpmb_key * rpmb_key,uint16_t rpmb_key_part_base,hwkey_session_t hwkey_session)449 static int block_device_tipc_init_rpmb_key(struct rpmb_state* state,
450                                            const struct rpmb_key* rpmb_key,
451                                            uint16_t rpmb_key_part_base,
452                                            hwkey_session_t hwkey_session) {
453     int ret = 0;
454 
455     if (rpmb_key) {
456         rpmb_set_key(state, rpmb_key);
457     } else {
458         ret = block_device_tipc_derive_rpmb_key(state, rpmb_key_part_base,
459                                                 hwkey_session);
460     }
461 
462     return ret;
463 }
464 
set_storage_size(handle_t handle,struct block_device_ns * dev_ns)465 static int set_storage_size(handle_t handle, struct block_device_ns* dev_ns) {
466     data_block_t sz;
467 
468     int ret = ns_get_max_size(handle, dev_ns->ns_handle, &sz);
469     if (ret < 0) {
470         /* In case we have an old storageproxyd, use default */
471         if (ret == ERR_NOT_IMPLEMENTED) {
472             sz = BLOCK_COUNT_MAIN * dev_ns->dev.block_size;
473             ret = 0;
474         } else {
475             SS_ERR("%s: Could not get max size: %d\n", __func__, ret);
476             return ret;
477         }
478     } else if (sz < (dev_ns->dev.block_size * 8)) {
479         SS_ERR("%s: max storage file size %" PRIu64 " is too small\n", __func__,
480                sz);
481         return -1;
482     }
483 
484     dev_ns->dev.block_count = sz / dev_ns->dev.block_size;
485     return ret;
486 }
487 
block_device_tipc_has_ns(struct block_device_tipc * self)488 static bool block_device_tipc_has_ns(struct block_device_tipc* self) {
489     return self->dev_ns.dev.block_count;
490 }
491 
492 /**
493  * init_rpmb_fs() - Initialize @self's RPMB fs and its backing block devices.
494  * @self:            The struct block_device_tipc to modify
495  * @fs_key:          The key to use for the filesystem.
496  * @partition_start: The first RPMB block in the partition to use for this fs.
497  *
498  * Return: NO_ERROR on success, error code less than 0 on error.
499  */
init_rpmb_fs(struct block_device_tipc * self,const struct key * fs_key,uint16_t partition_start)500 static int init_rpmb_fs(struct block_device_tipc* self,
501                         const struct key* fs_key,
502                         uint16_t partition_start) {
503     int ret;
504     uint32_t rpmb_block_count;
505 
506     if (BLOCK_COUNT_RPMB) {
507         rpmb_block_count = BLOCK_COUNT_RPMB;
508         ret = rpmb_check(self->rpmb_state,
509                          rpmb_block_count * BLOCK_SIZE_RPMB_BLOCKS - 1);
510         if (ret < 0) {
511             SS_ERR("%s: bad static rpmb size, %d\n", __func__,
512                    rpmb_block_count);
513             goto err_bad_rpmb_size;
514         }
515     } else {
516         rpmb_block_count = rpmb_search_size(self->rpmb_state,
517                                             0); /* TODO: get hint from ns */
518         rpmb_block_count /= BLOCK_SIZE_RPMB_BLOCKS;
519     }
520     if (rpmb_block_count < partition_start) {
521         ret = -1;
522         SS_ERR("%s: bad rpmb size, %d\n", __func__, rpmb_block_count);
523         goto err_bad_rpmb_size;
524     }
525 
526     block_device_tipc_init_dev_rpmb(&self->dev_rpmb, self->rpmb_state,
527                                     partition_start,
528                                     rpmb_block_count - partition_start, false);
529 
530     /* TODO: allow non-rpmb based tamper proof storage */
531     ret = fs_init(&self->tr_state_rpmb, file_system_id_tp, fs_key,
532                   &self->dev_rpmb.dev, &self->dev_rpmb.dev, FS_INIT_FLAGS_NONE);
533     if (ret < 0) {
534         SS_ERR("%s: failed to initialize TP: %d\n", __func__, ret);
535         goto err_init_tr_state_rpmb;
536     }
537     return 0;
538 
539 err_init_tr_state_rpmb:
540     block_cache_dev_destroy(&self->dev_rpmb.dev);
541 err_bad_rpmb_size:
542     return ret;
543 }
544 
545 /**
546  * destroy_rpmb_fs() - Destroy @self's RPMB fs and its backing block devices.
547  */
destroy_rpmb_fs(struct block_device_tipc * self)548 static void destroy_rpmb_fs(struct block_device_tipc* self) {
549     fs_destroy(&self->tr_state_rpmb);
550     block_cache_dev_destroy(&self->dev_rpmb.dev);
551 }
552 
553 /**
554  * block_device_ns_open_file() - Open an ns backing file
555  *
556  * @self: The ns block device to use to open the file.
557  * @name: The name of the file to open.
558  * @create: Whether the file should be created if it doesn't already exist.
559  *
560  * Return: NO_ERROR on success, error code less than 0 if an error was
561  * encountered during initialization.
562  */
block_device_ns_open_file(struct block_device_ns * self,const char * name,bool create)563 static int block_device_ns_open_file(struct block_device_ns* self,
564                                      const char* name,
565                                      bool create) {
566     return ns_open_file(self->ipc_handle, name, &self->ns_handle, create);
567 }
568 
569 /**
570  * block_device_ns_open_file_with_alternate() - Open an ns backing file,
571  * possibly falling back to an alternate if the primary is not available.
572  *
573  * @self:           The ns block device to use to open the file.
574  * @name:           The name of the primary file to open.
575  * @alternate_name: The name of the alternate file. Ignored if
576  *                  STORAGE_NS_ALTERNATE_SUPERBLOCK_ALLOWED is false.
577  * @create:         Whether the file should be created if it doesn't already
578  *                  exist.
579  * @used_alternate: Out-param, set only on successful return. Will tell whether
580  *                  the opened file was the alternate.
581  *
582  * Return: NO_ERROR on success, error code less than 0 if an error was
583  * encountered during initialization.
584  */
block_device_ns_open_file_with_alternate(struct block_device_ns * self,const char * name,const char * alternate_name,bool create,bool * used_alternate)585 static int block_device_ns_open_file_with_alternate(
586         struct block_device_ns* self,
587         const char* name,
588         const char* alternate_name,
589         bool create,
590         bool* used_alternate) {
591     int ret = block_device_ns_open_file(self, name, create);
592     if (ret >= 0) {
593         *used_alternate = false;
594         return NO_ERROR;
595     }
596 
597 #if STORAGE_NS_ALTERNATE_SUPERBLOCK_ALLOWED
598     ret = block_device_ns_open_file(self, alternate_name, create);
599     if (ret >= 0) {
600         *used_alternate = true;
601         return NO_ERROR;
602     }
603 #endif
604     return ret;
605 }
606 
607 enum ns_init_result {
608     /* Negative codes reserved for other error values. */
609     NS_INIT_SUCCESS = 0,
610     NS_INIT_NOT_READY = 1,
611 };
612 
613 /**
614  * init_ns_fs() - Initialize @self's NS fs and its backing block devices.
615  * @self:      The struct block_device_tipc to modify
616  * @fs_key:    The key to use for the filesystem.
617  * @partition: The RPMB blocks to use for the filesystem's superblocks.
618  *
619  * If no ns filesystems are available, return NS_INIT_NOT_READY and leave the NS
620  * fs uninitialized. (In that case, block_device_tipc_has_ns() will return
621  * false.)
622  *
623  * Return: NS_INIT_SUCCESS on success, NS_INIT_NOT_READY if ns is unavailable,
624  * or an error code less than 0 if an error was encountered during
625  * initialization.
626  */
init_ns_fs(struct block_device_tipc * self,const struct key * fs_key,struct rpmb_span partition)627 static int init_ns_fs(struct block_device_tipc* self,
628                       const struct key* fs_key,
629                       struct rpmb_span partition) {
630     block_device_tipc_init_dev_ns(&self->dev_ns, self->ipc_handle, true);
631 
632     bool alternate_data_partition;
633     int ret = block_device_ns_open_file_with_alternate(
634             &self->dev_ns, ns_filename, ns_alternate_filename, true,
635             &alternate_data_partition);
636     if (ret < 0) {
637         /* NS not available; init RPMB fs only */
638         self->dev_ns.dev.block_count = 0;
639         return NS_INIT_NOT_READY;
640     }
641 
642     ret = set_storage_size(self->ipc_handle, &self->dev_ns);
643     if (ret < 0) {
644         goto err_get_td_max_size;
645     }
646 
647     /* Request empty file system if file is empty */
648     uint8_t probe;
649     uint32_t ns_init_flags = FS_INIT_FLAGS_NONE;
650     ret = ns_read_pos(self->ipc_handle, self->dev_ns.ns_handle, 0, &probe,
651                       sizeof(probe));
652     if (ret < (int)sizeof(probe)) {
653         ns_init_flags |= FS_INIT_FLAGS_DO_CLEAR;
654     }
655 
656     block_device_tipc_init_dev_rpmb(&self->dev_ns_rpmb, self->rpmb_state,
657                                     partition.start, partition.block_count,
658                                     true);
659 
660 #if STORAGE_NS_RECOVERY_CLEAR_ALLOWED
661     ns_init_flags |= FS_INIT_FLAGS_RECOVERY_CLEAR_ALLOWED;
662 #endif
663 
664     /*
665      * This must be false if STORAGE_NS_ALTERNATE_SUPERBLOCK_ALLOWED is
666      * false.
667      */
668     if (alternate_data_partition) {
669         ns_init_flags |= FS_INIT_FLAGS_ALTERNATE_DATA;
670     }
671 
672     ret = fs_init(&self->tr_state_ns, file_system_id_td, fs_key,
673                   &self->dev_ns.dev, &self->dev_ns_rpmb.dev, ns_init_flags);
674     if (ret < 0) {
675         SS_ERR("%s: failed to initialize TD: %d\n", __func__, ret);
676         goto err_init_fs_ns_tr_state;
677     }
678 
679     return NS_INIT_SUCCESS;
680 
681 err_init_fs_ns_tr_state:
682     block_cache_dev_destroy(&self->dev_ns.dev);
683 err_get_td_max_size:
684     ns_close_file(self->ipc_handle, self->dev_ns.ns_handle);
685     return ret;
686 }
687 
688 /**
689  * destroy_ns_fs() - Destroy @self's NS fs and its backing block devices.
690  */
destroy_ns_fs(struct block_device_tipc * self)691 static void destroy_ns_fs(struct block_device_tipc* self) {
692     fs_destroy(&self->tr_state_ns);
693     block_cache_dev_destroy(&self->dev_ns.dev);
694 }
695 
696 #if HAS_FS_TDP
697 /**
698  * init_tdp_fs() - Initialize @self's TDP fs and its backing block devices.
699  * @self:      The struct block_device_tipc to modify
700  * @fs_key:    The key to use for the filesystem.
701  * @partition: The RPMB blocks to use for the filesystem's superblocks.
702  *
703  * Return: NO_ERROR on success, error code less than 0 on error.
704  */
init_tdp_fs(struct block_device_tipc * self,const struct key * fs_key,struct rpmb_span partition)705 static int init_tdp_fs(struct block_device_tipc* self,
706                        const struct key* fs_key,
707                        struct rpmb_span partition) {
708     block_device_tipc_init_dev_ns(&self->dev_ns_tdp, self->ipc_handle, false);
709 
710     int ret = block_device_ns_open_file(&self->dev_ns_tdp, tdp_filename, true);
711     if (ret < 0) {
712         SS_ERR("%s: failed to open tdp file (%d)\n", __func__, ret);
713         goto err_open_tdp;
714     }
715 
716     ret = set_storage_size(self->ipc_handle, &self->dev_ns_tdp);
717     if (ret < 0) {
718         goto err_get_tdp_max_size;
719     }
720 
721     block_device_tipc_init_dev_rpmb(&self->dev_ns_tdp_rpmb, self->rpmb_state,
722                                     partition.start, partition.block_count,
723                                     false);
724 
725     uint32_t tdp_init_flags = FS_INIT_FLAGS_NONE;
726 #if STORAGE_TDP_AUTO_CHECKPOINT_ENABLED
727     if (!system_state_provisioning_allowed()) {
728         /*
729          * Automatically create a checkpoint if we are done provisioning but do
730          * not already have a checkpoint.
731          */
732         tdp_init_flags |= FS_INIT_FLAGS_AUTO_CHECKPOINT;
733     }
734 #endif
735 
736     ret = fs_init(&self->tr_state_ns_tdp, file_system_id_tdp, fs_key,
737                   &self->dev_ns_tdp.dev, &self->dev_ns_tdp_rpmb.dev,
738                   tdp_init_flags);
739     if (ret < 0) {
740         goto err_init_fs_ns_tdp_tr_state;
741     }
742 
743 #if STORAGE_TDP_RECOVERY_CHECKPOINT_RESTORE_ALLOWED
744     if (fs_check(&self->tr_state_ns_tdp) == FS_CHECK_INVALID_BLOCK) {
745         SS_ERR("%s: TDP filesystem check failed with invalid block, "
746                "attempting to restore checkpoint\n",
747                __func__);
748         fs_destroy(&self->tr_state_ns_tdp);
749         ret = fs_init(&self->tr_state_ns_tdp, file_system_id_tdp, fs_key,
750                       &self->dev_ns_tdp.dev, &self->dev_ns_tdp_rpmb.dev,
751                       tdp_init_flags | FS_INIT_FLAGS_RESTORE_CHECKPOINT);
752         if (ret < 0) {
753             SS_ERR("%s: failed to initialize TDP: %d\n", __func__, ret);
754             goto err_init_fs_ns_tdp_tr_state;
755         }
756     }
757 #endif
758 
759     return 0;
760 
761 err_init_fs_ns_tdp_tr_state:
762     block_cache_dev_destroy(&self->dev_ns_tdp.dev);
763 err_get_tdp_max_size:
764     ns_close_file(self->ipc_handle, self->dev_ns_tdp.ns_handle);
765 err_open_tdp:
766     return ret;
767 }
768 
769 /**
770  * destroy_tdp_fs() - Destroy @self's TDP fs and its backing block devices.
771  */
destroy_tdp_fs(struct block_device_tipc * self)772 static void destroy_tdp_fs(struct block_device_tipc* self) {
773     fs_destroy(&self->tr_state_ns_tdp);
774     block_cache_dev_destroy(&self->dev_ns_tdp.dev);
775 }
776 #endif
777 
778 #if HAS_FS_NSP
779 /**
780  * init_nsp_fs() - Initialize @self's NSP fs and its backing block devices.
781  * @self:      The struct block_device_tipc to modify
782  * @fs_key:    The key to use for the filesystem.
783  *
784  * Return: NO_ERROR on success, error code less than 0 on error.
785  */
init_nsp_fs(struct block_device_tipc * self,const struct key * fs_key)786 static int init_nsp_fs(struct block_device_tipc* self,
787                        const struct key* fs_key) {
788     block_device_tipc_init_dev_ns(&self->dev_ns_nsp, self->ipc_handle, false);
789 
790     int ret = block_device_ns_open_file(&self->dev_ns_nsp, nsp_filename, true);
791     if (ret < 0) {
792         SS_ERR("%s: failed to open NSP file (%d)\n", __func__, ret);
793         goto err_open_nsp;
794     }
795 
796     ret = set_storage_size(self->ipc_handle, &self->dev_ns_nsp);
797     if (ret < 0) {
798         goto err_get_nsp_max_size;
799     }
800 
801     ret = fs_init(&self->tr_state_ns_nsp, file_system_id_nsp, fs_key,
802                   &self->dev_ns_nsp.dev, &self->dev_ns_nsp.dev,
803                   FS_INIT_FLAGS_RECOVERY_CLEAR_ALLOWED |
804                           FS_INIT_FLAGS_ALLOW_TAMPERING);
805     if (ret < 0) {
806         SS_ERR("%s: failed to initialize NSP: %d\n", __func__, ret);
807         goto err_init_fs_ns_nsp_tr_state;
808     }
809 
810     /*
811      * Check that all files are accessible and attempt to clear the FS if files
812      * cannot be accessed.
813      */
814     if (fs_check(&self->tr_state_ns_nsp) != FS_CHECK_NO_ERROR) {
815         SS_ERR("%s: NSP filesystem check failed, attempting to clear\n",
816                __func__);
817         fs_destroy(&self->tr_state_ns_nsp);
818         block_cache_dev_destroy(&self->dev_ns_nsp.dev);
819 
820         ret = fs_init(&self->tr_state_ns_nsp, file_system_id_nsp, fs_key,
821                       &self->dev_ns_nsp.dev, &self->dev_ns_nsp.dev,
822                       FS_INIT_FLAGS_DO_CLEAR | FS_INIT_FLAGS_ALLOW_TAMPERING);
823         if (ret < 0) {
824             SS_ERR("%s: failed to initialize NSP: %d\n", __func__, ret);
825             goto err_init_fs_ns_nsp_tr_state;
826         }
827     }
828     return 0;
829 
830 err_init_fs_ns_nsp_tr_state:
831     block_cache_dev_destroy(&self->dev_ns_nsp.dev);
832 err_get_nsp_max_size:
833     ns_close_file(self->ipc_handle, self->dev_ns_nsp.ns_handle);
834 err_open_nsp:
835     return ret;
836 }
837 
838 /**
839  * destroy_nsp_fs() - Destroy @self's NSP fs and its backing block devices.
840  */
destroy_nsp_fs(struct block_device_tipc * self)841 static void destroy_nsp_fs(struct block_device_tipc* self) {
842     fs_destroy(&self->tr_state_ns_nsp);
843     block_cache_dev_destroy(&self->dev_ns_nsp.dev);
844 }
845 #endif
846 
block_device_ns_disconnect(struct block_device_ns * self)847 static void block_device_ns_disconnect(struct block_device_ns* self) {
848     if (self->ipc_handle != INVALID_IPC_HANDLE) {
849         ns_close_file(self->ipc_handle, self->ns_handle);
850         self->ipc_handle = INVALID_IPC_HANDLE;
851     }
852 }
853 
init_ns_backed_filesystems(struct block_device_tipc * self,const struct key * fs_key,struct rpmb_span ns_partition,struct rpmb_span tdp_partition)854 static int init_ns_backed_filesystems(struct block_device_tipc* self,
855                                       const struct key* fs_key,
856                                       struct rpmb_span ns_partition,
857                                       struct rpmb_span tdp_partition) {
858     int ret = init_ns_fs(self, fs_key, ns_partition);
859     if (ret == NS_INIT_NOT_READY) {
860         /* If we don't currently have ns access, we didn't actually initialize
861          * `tr_state_ns`. Trying to init any other ns-dependent fs would fail,
862          * so skip them. */
863         assert(!block_device_tipc_has_ns(self));
864         return 0;
865     } else if (ret < 0) {
866         goto err_init_ns_fs;
867     }
868 
869 #if HAS_FS_TDP
870     ret = init_tdp_fs(self, fs_key, tdp_partition);
871     if (ret < 0) {
872         goto err_init_tdp_fs;
873     }
874 #endif
875 
876 #if HAS_FS_NSP
877     ret = init_nsp_fs(self, fs_key);
878     if (ret < 0) {
879         goto err_init_nsp_fs;
880     }
881 #endif
882 
883     return 0;
884 
885 #if HAS_FS_NSP
886 err_init_nsp_fs:
887 #endif
888 #if HAS_FS_TDP
889     block_device_ns_disconnect(&self->dev_ns_tdp);
890     destroy_tdp_fs(self);
891 err_init_tdp_fs:
892 #endif
893     block_device_ns_disconnect(&self->dev_ns);
894     destroy_ns_fs(self);
895 err_init_ns_fs:
896     return ret;
897 }
898 
899 /**
900  * rpmb_span_end() - Calculates the first block past the end of @self.
901  */
rpmb_span_end(struct rpmb_span self)902 static uint16_t rpmb_span_end(struct rpmb_span self) {
903     return self.start + self.block_count;
904 }
905 
906 /**
907  * calculate_rpmb_spans() - Determines the starts and sizes of RPMB partitions.
908  */
calculate_rpmb_spans(struct rpmb_spans * out)909 static void calculate_rpmb_spans(struct rpmb_spans* out) {
910     out->key.block_count = 1;
911     /* Used to store superblocks */
912     out->ns.block_count = 2;
913 #if HAS_FS_TDP
914     out->tdp.block_count = out->ns.block_count;
915 #else
916     out->tdp.block_count = 0;
917 #endif
918 
919     out->key.start = 0;
920     out->ns.start = rpmb_span_end(out->key);
921     out->tdp.start = rpmb_span_end(out->ns);
922     out->rpmb_start = rpmb_span_end(out->tdp);
923 }
924 
block_device_tipc_init(struct block_device_tipc * state,handle_t ipc_handle,const struct key * fs_key,const struct rpmb_key * rpmb_key,hwkey_session_t hwkey_session)925 int block_device_tipc_init(struct block_device_tipc* state,
926                            handle_t ipc_handle,
927                            const struct key* fs_key,
928                            const struct rpmb_key* rpmb_key,
929                            hwkey_session_t hwkey_session) {
930     int ret;
931     struct rpmb_spans partitions;
932     calculate_rpmb_spans(&partitions);
933 
934     state->ipc_handle = ipc_handle;
935 
936     /* init rpmb */
937     ret = rpmb_init(&state->rpmb_state, &state->ipc_handle);
938     if (ret < 0) {
939         SS_ERR("%s: rpmb_init failed (%d)\n", __func__, ret);
940         goto err_rpmb_init;
941     }
942 
943     ret = block_device_tipc_init_rpmb_key(state->rpmb_state, rpmb_key,
944                                           partitions.key.start, hwkey_session);
945     if (ret < 0) {
946         SS_ERR("%s: block_device_tipc_init_rpmb_key failed (%d)\n", __func__,
947                ret);
948         goto err_init_rpmb_key;
949     }
950 
951     ret = init_rpmb_fs(state, fs_key, partitions.rpmb_start);
952     if (ret < 0) {
953         goto err_init_rpmb_fs;
954     }
955 
956     ret = init_ns_backed_filesystems(state, fs_key, partitions.ns,
957                                      partitions.tdp);
958     if (ret < 0) {
959         goto err_init_ns_fs;
960     }
961 
962     return 0;
963 
964 err_init_ns_fs:
965     destroy_rpmb_fs(state);
966 err_init_rpmb_fs:
967 err_init_rpmb_key:
968     rpmb_uninit(state->rpmb_state);
969 err_rpmb_init:
970     return ret;
971 }
972 
block_device_tipc_destroy(struct block_device_tipc * state)973 void block_device_tipc_destroy(struct block_device_tipc* state) {
974     if (block_device_tipc_has_ns(state)) {
975 #if HAS_FS_NSP
976         destroy_nsp_fs(state);
977 #endif
978 #if HAS_FS_TDP
979         destroy_tdp_fs(state);
980 #endif
981         destroy_ns_fs(state);
982     }
983 
984     destroy_rpmb_fs(state);
985     rpmb_uninit(state->rpmb_state);
986 }
987 
block_device_tipc_fs_connected(struct block_device_tipc * self,enum storage_filesystem_type fs_type)988 bool block_device_tipc_fs_connected(struct block_device_tipc* self,
989                                     enum storage_filesystem_type fs_type) {
990     switch (fs_type) {
991     case STORAGE_TP:
992         return self->ipc_handle != INVALID_IPC_HANDLE;
993     case STORAGE_TDEA:
994         return self->ipc_handle != INVALID_IPC_HANDLE;
995     case STORAGE_TD:
996         return block_device_tipc_has_ns(self) &&
997                self->dev_ns.ipc_handle != INVALID_IPC_HANDLE;
998     case STORAGE_TDP:
999 #if HAS_FS_TDP
1000         return block_device_tipc_has_ns(self) &&
1001                self->dev_ns_tdp.ipc_handle != INVALID_IPC_HANDLE;
1002 #else
1003         return block_device_tipc_fs_connected(self, STORAGE_TP);
1004 #endif
1005     case STORAGE_NSP:
1006 #if HAS_FS_NSP
1007         return block_device_tipc_has_ns(self) &&
1008                self->dev_ns_nsp.ipc_handle != INVALID_IPC_HANDLE;
1009 #else
1010         return block_device_tipc_fs_connected(self, STORAGE_TDP);
1011 #endif
1012     case STORAGE_FILESYSTEMS_COUNT:
1013     default:
1014         SS_ERR("%s: Tried to check fs of unrecognized storage_filesystem type: (%d)\n",
1015                __func__, fs_type);
1016         return false;
1017     }
1018 }
1019 
block_device_tipc_get_fs(struct block_device_tipc * self,enum storage_filesystem_type fs_type)1020 struct fs* block_device_tipc_get_fs(struct block_device_tipc* self,
1021                                     enum storage_filesystem_type fs_type) {
1022     assert(block_device_tipc_fs_connected(self, fs_type));
1023 
1024     switch (fs_type) {
1025     case STORAGE_TP:
1026         return &self->tr_state_rpmb;
1027     case STORAGE_TDEA:
1028         return &self->tr_state_rpmb;
1029     case STORAGE_TD:
1030         return &self->tr_state_ns;
1031     case STORAGE_TDP:
1032 #if HAS_FS_TDP
1033         return &self->tr_state_ns_tdp;
1034 #else
1035         return block_device_tipc_get_fs(self, STORAGE_TP);
1036 #endif
1037     case STORAGE_NSP:
1038 #if HAS_FS_NSP
1039         return &self->tr_state_ns_nsp;
1040 #else
1041         return block_device_tipc_get_fs(self, STORAGE_TDP);
1042 #endif
1043     case STORAGE_FILESYSTEMS_COUNT:
1044     default:
1045         SS_ERR("%s: Tried to init fs of unrecognized storage_filesystem type: (%d)\n",
1046                __func__, fs_type);
1047         return NULL;
1048     }
1049 }
1050 
block_device_tipc_reconnect(struct block_device_tipc * self,handle_t ipc_handle,const struct key * fs_key)1051 int block_device_tipc_reconnect(struct block_device_tipc* self,
1052                                 handle_t ipc_handle,
1053                                 const struct key* fs_key) {
1054     int ret;
1055 
1056     assert(self->ipc_handle == INVALID_IPC_HANDLE);
1057     /* rpmb_state keeps a pointer to this handle, so updating here will cause
1058      * all the rpmb connections to use the new handle. */
1059     self->ipc_handle = ipc_handle;
1060 
1061     bool has_ns = block_device_tipc_has_ns(self);
1062     if (!has_ns) {
1063         struct rpmb_spans partitions;
1064         calculate_rpmb_spans(&partitions);
1065         ret = init_ns_backed_filesystems(self, fs_key, partitions.ns,
1066                                          partitions.tdp);
1067         if (ret < 0) {
1068             SS_ERR("%s: failed to init NS backed filesystems (%d)\n", __func__,
1069                    ret);
1070             return ret;
1071         }
1072         return 0;
1073     }
1074 
1075     bool alternate_data_partition;
1076     self->dev_ns.ipc_handle = ipc_handle;
1077     ret = block_device_ns_open_file_with_alternate(&self->dev_ns, ns_filename,
1078                                                    ns_alternate_filename, false,
1079                                                    &alternate_data_partition);
1080     if (ret < 0) {
1081         /* NS not available right now; leave NS filesystems disconnected. */
1082         self->dev_ns.ipc_handle = INVALID_IPC_HANDLE;
1083         SS_ERR("%s: failed to reconnect ns filesystem (%d)\n", __func__, ret);
1084         return 0;
1085     }
1086     assert(alternate_data_partition == self->tr_state_ns.alternate_data);
1087 #if HAS_FS_TDP
1088     self->dev_ns_tdp.ipc_handle = ipc_handle;
1089     ret = block_device_ns_open_file(&self->dev_ns_tdp, tdp_filename, false);
1090     if (ret < 0) {
1091         SS_ERR("%s: failed to reconnect tdp filesystem (%d)\n", __func__, ret);
1092         self->dev_ns_tdp.ipc_handle = INVALID_IPC_HANDLE;
1093         goto err_reconnect_tdp;
1094     }
1095 #endif
1096 #if HAS_FS_NSP
1097     self->dev_ns_nsp.ipc_handle = ipc_handle;
1098     ret = block_device_ns_open_file(&self->dev_ns_nsp, nsp_filename, false);
1099     if (ret < 0) {
1100         SS_ERR("%s: failed to reconnect nsp filesystem (%d)\n", __func__, ret);
1101         self->dev_ns_nsp.ipc_handle = INVALID_IPC_HANDLE;
1102         goto err_reconnect_nsp;
1103     }
1104 #endif
1105 
1106     return 0;
1107 #if HAS_FS_NSP
1108 err_reconnect_nsp:
1109 #endif
1110 #if HAS_FS_TDP
1111     block_device_ns_disconnect(&self->dev_ns_tdp);
1112 err_reconnect_tdp:
1113 #endif
1114     block_device_ns_disconnect(&self->dev_ns);
1115     return ret;
1116 }
1117 
block_device_tipc_disconnect(struct block_device_tipc * self)1118 void block_device_tipc_disconnect(struct block_device_tipc* self) {
1119     /* Must currently be connected to disconnect */
1120     assert(self->ipc_handle != INVALID_IPC_HANDLE);
1121     /* Disconnects rpmb */
1122     self->ipc_handle = INVALID_IPC_HANDLE;
1123 
1124     if (block_device_tipc_has_ns(self)) {
1125         block_device_ns_disconnect(&self->dev_ns);
1126 #if HAS_FS_TDP
1127         block_device_ns_disconnect(&self->dev_ns_tdp);
1128 #endif
1129 #if HAS_FS_NSP
1130         block_device_ns_disconnect(&self->dev_ns_nsp);
1131 #endif
1132     }
1133 }
1134