Merge branch 'upstream' into tizen
[platform/upstream/cryptsetup.git] / lib / verity / verity_fec.c
index e076c97..2dbf59e 100644 (file)
@@ -2,7 +2,7 @@
  * dm-verity Forward Error Correction (FEC) support
  *
  * Copyright (C) 2015 Google, Inc. All rights reserved.
- * Copyright (C) 2017-2021 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2017-2023 Red Hat, Inc. All rights reserved.
  *
  * This file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -178,6 +178,7 @@ static int FEC_process_inputs(struct crypt_device *cd,
                                r = decode_rs_char(rs, rs_block);
                                if (r < 0) {
                                        log_err(cd, _("Failed to repair parity for block %" PRIu64 "."), n);
+                                       r = -EPERM;
                                        goto out;
                                }
                                /* return number of detected errors */
@@ -201,6 +202,22 @@ out:
        return r;
 }
 
+static int VERITY_FEC_validate(struct crypt_device *cd, struct crypt_params_verity *params)
+{
+       if (params->data_block_size != params->hash_block_size) {
+               log_err(cd, _("Block sizes must match for FEC."));
+               return -EINVAL;
+       }
+
+       if (params->fec_roots > FEC_RSM - FEC_MIN_RSN ||
+               params->fec_roots < FEC_RSM - FEC_MAX_RSN) {
+               log_err(cd, _("Invalid number of parity bytes."));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int VERITY_FEC_process(struct crypt_device *cd,
                      struct crypt_params_verity *params,
                      struct device *fec_device, int check_fec,
@@ -223,16 +240,9 @@ int VERITY_FEC_process(struct crypt_device *cd,
        };
 
        /* validate parameters */
-       if (params->data_block_size != params->hash_block_size) {
-               log_err(cd, _("Block sizes must match for FEC."));
-               return -EINVAL;
-       }
-
-       if (params->fec_roots > FEC_RSM - FEC_MIN_RSN ||
-               params->fec_roots < FEC_RSM - FEC_MAX_RSN) {
-               log_err(cd, _("Invalid number of parity bytes."));
-               return -EINVAL;
-       }
+       r = VERITY_FEC_validate(cd, params);
+       if (r < 0)
+               return r;
 
        if (!inputs[0].count) {
                log_err(cd, _("Invalid FEC segment length."));
@@ -280,12 +290,16 @@ out:
        return r;
 }
 
+/* All blocks that are covered by FEC */
 uint64_t VERITY_FEC_blocks(struct crypt_device *cd,
                           struct device *fec_device,
                           struct crypt_params_verity *params)
 {
        uint64_t blocks = 0;
 
+       if (!fec_device || VERITY_FEC_validate(cd, params) < 0)
+               return 0;
+
        /*
        * FEC covers this data:
        *     | protected data | hash area | padding (optional foreign metadata) |
@@ -314,3 +328,9 @@ uint64_t VERITY_FEC_blocks(struct crypt_device *cd,
 
        return blocks;
 }
+
+/* Blocks needed to store FEC data, blocks must be validated/calculated by VERITY_FEC_blocks() */
+uint64_t VERITY_FEC_RS_blocks(uint64_t blocks, uint32_t roots)
+{
+       return FEC_div_round_up(blocks, FEC_RSM - roots) * roots;
+}