[Devel] [PATCH VZ9 1/2] fs/fuse: pcs: corrupted writes in encrypted journalless mode

Alexey Kuznetsov kuznet at virtuozzo.com
Fri Apr 26 18:19:02 MSK 2024


It is a shame. The bug is stupid and effect is disasterous.

https://pmc.acronis.work/browse/VSTOR-84977

Signed-off-by: Alexey Kuznetsov <kuznet at acronis.com>
---
 fs/fuse/kio/pcs/pcs_cs_accel.c | 43 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_cs_accel.c b/fs/fuse/kio/pcs/pcs_cs_accel.c
index a18069f..9be94a6 100644
--- a/fs/fuse/kio/pcs/pcs_cs_accel.c
+++ b/fs/fuse/kio/pcs/pcs_cs_accel.c
@@ -932,7 +932,8 @@ static int init_crypted_data(struct pcs_int_request * ireq, int idx)
 	struct pcs_int_request *parent = ireq->completion_data.parent;
 	struct pcs_fuse_req * r;
 	struct bio_vec * bvec;
-	int n, nvec;
+	int n, nvec, first;
+	unsigned int off, start_off, end_off;
 	u64 pos;
 	u64 chunk_id;
 	struct pcs_csa_context * csa_ctx;
@@ -951,14 +952,38 @@ static int init_crypted_data(struct pcs_int_request * ireq, int idx)
 	if (!bvec)
 		return -ENOMEM;
 
-	for (n = 0; n < nvec; n++) {
-		bvec[n] = r->exec.io.bvec[n];
-		if ((bvec[n].bv_offset|bvec[n].bv_len)&511)
+	off = 0;
+	start_off = ireq->iochunk.dio_offset;
+	end_off = start_off + ireq->iochunk.size;
+
+	for (first = 0; first < nvec; first++) {
+		struct bio_vec *v = r->exec.io.bvec + first;
+		unsigned int next = off + v->bv_len;
+
+		if (next > start_off)
+			break;
+		off = next;
+	}
+
+	for (n = 0; n < nvec - first && off < end_off; n++) {
+		struct bio_vec *v = r->exec.io.bvec + first + n;
+		unsigned int next = off + v->bv_len;
+
+		bvec[n] = *v;
+		if (off < start_off) {
+			bvec[n].bv_offset += start_off - off;
+			bvec[n].bv_len -= start_off - off;
+		}
+		if (next > end_off)
+			bvec[n].bv_len -= next - end_off;
+		if ((bvec[n].bv_offset | bvec[n].bv_len) & 511)
 			goto out;
 		bvec[n].bv_page = alloc_page(GFP_NOIO);
 		if (!bvec[n].bv_page)
 			goto out;
+		off = next;
 	}
+	nvec = n;
 
 	rcu_read_lock();
 	csa_ctx = rcu_dereference(ireq->iochunk.csl->cs[idx].cslink.cs->csa_ctx);
@@ -969,17 +994,19 @@ static int init_crypted_data(struct pcs_int_request * ireq, int idx)
 
 	pos = ireq->iochunk.offset;
 	chunk_id = ireq->iochunk.map->id;
-	for (n = 0; n < nvec; n++) {
+	for (n = 0; n < nvec; n++, first++) {
 		if (tfm->base.base.__crt_alg->cra_priority == 400)
-			encrypt_page_ctr(tfm, bvec[n].bv_page, r->exec.io.bvec[n].bv_page, bvec[n].bv_offset, bvec[n].bv_len, pos, chunk_id);
+			encrypt_page_ctr(tfm, bvec[n].bv_page, r->exec.io.bvec[first].bv_page,
+					 bvec[n].bv_offset, bvec[n].bv_len, pos, chunk_id);
 		else
-			encrypt_page_xts(tfm, bvec[n].bv_page, r->exec.io.bvec[n].bv_page, bvec[n].bv_offset, bvec[n].bv_len, pos, chunk_id);
+			encrypt_page_xts(tfm, bvec[n].bv_page, r->exec.io.bvec[first].bv_page,
+					 bvec[n].bv_offset, bvec[n].bv_len, pos, chunk_id);
 		pos += bvec[n].bv_len;
 	}
 	rcu_read_unlock();
 
 	ireq->iochunk.acr.awr[idx].bvec_copy = bvec;
-	ireq->iochunk.acr.awr[idx].num_copy_bvecs = n;
+	ireq->iochunk.acr.awr[idx].num_copy_bvecs = nvec;
 	return 0;
 
 out:
-- 
1.8.3.1



More information about the Devel mailing list