From 45af6c5fc385f2c948bdb387585b3e0a41ccbcde Mon Sep 17 00:00:00 2001 From: Edward Shishkin Date: Mon, 27 Oct 2014 21:35:16 +0100 Subject: Prevent metadata corruption in the race conditions between FOP->open() and FOP->link(). Problem: crypt_open() modifies @local->format, which is used by crypt_link() to store the updated metadata string on disk. This results in metadata corruption. Fixup: Don't modify @local->format by FOP->open(). Instead modify a local copy, allocated in the low-level meta-data handler open_format_v1(). Change-Id: I046bb39ddefc33afe59c8d3b1a2fa798298f8499 BUG: 1157839 Signed-off-by: Edward Shishkin Reviewed-on: http://review.gluster.org/8982 Reviewed-by: Emmanuel Dreyfus Tested-by: Emmanuel Dreyfus Tested-by: Gluster Build System --- xlators/encryption/crypt/src/metadata.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'xlators/encryption/crypt') diff --git a/xlators/encryption/crypt/src/metadata.c b/xlators/encryption/crypt/src/metadata.c index 36b14c0558e..ebc76c84eb2 100644 --- a/xlators/encryption/crypt/src/metadata.c +++ b/xlators/encryption/crypt/src/metadata.c @@ -475,24 +475,30 @@ static int32_t open_format_v1(unsigned char *wire, num_nmtd_macs = check_format_v1(len, wire); if (num_nmtd_macs <= 0) return EIO; - fmt = (struct mtd_format_v1 *)wire; - ret = lookup_link_mac_v1(fmt, num_nmtd_macs, loc, info, master); + ret = lookup_link_mac_v1((struct mtd_format_v1 *)wire, + num_nmtd_macs, loc, info, master); if (ret < 0) { gf_log("crypt", GF_LOG_ERROR, "NMTD verification failed"); return EINVAL; } + local->mac_idx = ret; if (load_info == _gf_false) /* the case of partial open */ return 0; + fmt = GF_CALLOC(1, len, gf_crypt_mt_mtd); + if (!fmt) + return ENOMEM; + memcpy(fmt, wire, len); + object = &info->cinfo; ret = get_emtd_file_key(info, master, mtd_key); if (ret) { gf_log("crypt", GF_LOG_ERROR, "Can not retrieve metadata key"); - return ret; + goto out; } /* * decrypt encrypted meta-data @@ -500,12 +506,14 @@ static int32_t open_format_v1(unsigned char *wire, ret = AES_set_encrypt_key(mtd_key, sizeof(mtd_key)*8, &EMTD_KEY); if (ret < 0) { gf_log("crypt", GF_LOG_ERROR, "Can not set encrypt key"); - return ret; + ret = EIO; + goto out; } gctx = CRYPTO_gcm128_new(&EMTD_KEY, (block128_f)AES_encrypt); if (!gctx) { gf_log("crypt", GF_LOG_ERROR, "Can not alloc gcm context"); - return ENOMEM; + ret = ENOMEM; + goto out; } CRYPTO_gcm128_setiv(gctx, info->oid, sizeof(uuid_t)); @@ -514,7 +522,8 @@ static int32_t open_format_v1(unsigned char *wire, if (ret) { gf_log("crypt", GF_LOG_ERROR, " CRYPTO_gcm128_aad failed"); CRYPTO_gcm128_release(gctx); - return ret; + ret = EIO; + goto out; } ret = CRYPTO_gcm128_decrypt(gctx, get_EMTD_V1(fmt), @@ -523,7 +532,8 @@ static int32_t open_format_v1(unsigned char *wire, if (ret) { gf_log("crypt", GF_LOG_ERROR, " CRYPTO_gcm128_decrypt failed"); CRYPTO_gcm128_release(gctx); - return ret; + ret = EIO; + goto out; } /* * verify metadata @@ -532,7 +542,8 @@ static int32_t open_format_v1(unsigned char *wire, CRYPTO_gcm128_release(gctx); if (memcmp(gmac, get_EMTD_V1_MAC(fmt), SIZE_OF_EMTD_V1_MAC)) { gf_log("crypt", GF_LOG_ERROR, "EMTD verification failed"); - return EINVAL; + ret = EINVAL; + goto out; } /* * load verified metadata to the private part of inode @@ -544,7 +555,10 @@ static int32_t open_format_v1(unsigned char *wire, object->o_block_bits = fmt->block_bits; object->o_mode = fmt->mode_id; - return check_file_metadata(info); + ret = check_file_metadata(info); + out: + GF_FREE(fmt); + return ret; } /* -- cgit