diff options
author | Edward Shishkin <edward@redhat.com> | 2014-10-27 21:35:16 +0100 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-11-30 21:41:27 -0800 |
commit | 45af6c5fc385f2c948bdb387585b3e0a41ccbcde (patch) | |
tree | d06364c2d4912ae1363e43bf6fb402f0478a08e8 /xlators/encryption/crypt | |
parent | dcbab25710aa60a22708a0de8c41735bfca06d07 (diff) |
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 <edward@redhat.com>
Reviewed-on: http://review.gluster.org/8982
Reviewed-by: Emmanuel Dreyfus <manu@netbsd.org>
Tested-by: Emmanuel Dreyfus <manu@netbsd.org>
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Diffstat (limited to 'xlators/encryption/crypt')
-rw-r--r-- | xlators/encryption/crypt/src/metadata.c | 32 |
1 files changed, 23 insertions, 9 deletions
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; } /* |