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 | |
| 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>
| -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;  }  /*  | 
