diff options
author | Edward Shishkin <edward@redhat.com> | 2014-12-01 22:15:02 +0100 |
---|---|---|
committer | Raghavendra Bhat <raghavendra@redhat.com> | 2014-12-09 22:25:47 -0800 |
commit | b7d71e6541bc9c4a33cc5b46e93524ca1990c0bf (patch) | |
tree | 4deacfe311687ba6ae882cab6adc470171a404d4 /xlators/encryption | |
parent | 3e2c08d3ea6b90345e626f05dc2f0f77be039188 (diff) |
Prevent metadata corruption in the race conditions between
FOP->open() and FOP->link().
Backport of http://review.gluster.org/8982
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: Ife5bcb87de6db6d7ba5b65743adce86b2e3da890
BUG: 1169517
Signed-off-by: Edward Shishkin <edward@redhat.com>
Reviewed-on: http://review.gluster.org/9225
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Emmanuel Dreyfus <manu@netbsd.org>
Reviewed-by: Raghavendra Bhat <raghavendra@redhat.com>
Tested-by: Raghavendra Bhat <raghavendra@redhat.com>
Diffstat (limited to 'xlators/encryption')
-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; } /* |