From cd0cfcf3a825c6ea4c943d609fb5a3e391f81b01 Mon Sep 17 00:00:00 2001
From: Pranith Kumar K <pkarampu@redhat.com>
Date: Tue, 7 Jul 2015 12:40:42 +0530
Subject: [PATCH 212/212] cluster/ec: Fix use after free bug
Backport of http://review.gluster.org/11558
In ec_lock() there is a chance that ec_resume is called on fop even before
ec_sleep. This can result in refs == 0 for fop leading to use after free in
this function when it calls ec_sleep so do ec_sleep at start and ec_resume at
end of this function.
Change-Id: I879b2667bf71eaa56be1b53b5bdc91b7bb56c650
BUG: 1240245
Signed-off-by: Pranith Kumar K <pkarampu@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/52473
---
xlators/cluster/ec/src/ec-common.c | 8 ++++++++
xlators/cluster/ec/src/ec-data.c | 1 +
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/xlators/cluster/ec/src/ec-common.c b/xlators/cluster/ec/src/ec-common.c
index 200aeda..439773e 100644
--- a/xlators/cluster/ec/src/ec-common.c
+++ b/xlators/cluster/ec/src/ec-common.c
@@ -244,6 +244,7 @@ void ec_sleep(ec_fop_data_t *fop)
{
LOCK(&fop->lock);
+ GF_ASSERT (fop->refs > 0);
fop->refs++;
fop->jobs++;
@@ -1319,6 +1320,12 @@ void ec_lock(ec_fop_data_t *fop)
ec_lock_link_t *timer_link = NULL;
ec_lock_t *lock;
+ /* There is a chance that ec_resume is called on fop even before ec_sleep.
+ * Which can result in refs == 0 for fop leading to use after free in this
+ * function when it calls ec_sleep so do ec_sleep at start and ec_resume at
+ * the end of this function.*/
+ ec_sleep (fop);
+
while (fop->locked < fop->lock_count) {
/* Since there are only up to 2 locks per fop, this xor will change
* the order of the locks if fop->first_lock is 1. */
@@ -1383,6 +1390,7 @@ void ec_lock(ec_fop_data_t *fop)
timer_link = NULL;
}
}
+ ec_resume (fop, 0);
if (timer_link != NULL) {
ec_resume(timer_link->fop, 0);
diff --git a/xlators/cluster/ec/src/ec-data.c b/xlators/cluster/ec/src/ec-data.c
index 2a34f78..78c505c 100644
--- a/xlators/cluster/ec/src/ec-data.c
+++ b/xlators/cluster/ec/src/ec-data.c
@@ -258,6 +258,7 @@ void ec_fop_data_release(ec_fop_data_t * fop)
ec_trace("RELEASE", fop, "");
+ GF_ASSERT (fop->refs > 0);
refs = --fop->refs;
UNLOCK(&fop->lock);
--
1.7.1