Skip to content

Commit 42e15d1

Browse files
Mikulas PatockaMike Snitzer
authored andcommitted
dm-crypt: recheck the integrity tag after a failure
If a userspace process reads (with O_DIRECT) multiple blocks into the same buffer, dm-crypt reports an authentication error [1]. The error is reported in a log and it may cause RAID leg being kicked out of the array. This commit fixes dm-crypt, so that if integrity verification fails, the data is read again into a kernel buffer (where userspace can't modify it) and the integrity tag is rechecked. If the recheck succeeds, the content of the kernel buffer is copied into the user buffer; if the recheck fails, an integrity error is reported. [1] https://people.redhat.com/~mpatocka/testcases/blk-auth-modify/read2.c Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Mike Snitzer <snitzer@kernel.org>
1 parent 50c7024 commit 42e15d1

File tree

1 file changed

+73
-16
lines changed

1 file changed

+73
-16
lines changed

drivers/md/dm-crypt.c

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ struct convert_context {
6262
struct skcipher_request *req;
6363
struct aead_request *req_aead;
6464
} r;
65+
bool aead_recheck;
66+
bool aead_failed;
6567

6668
};
6769

@@ -82,6 +84,8 @@ struct dm_crypt_io {
8284
blk_status_t error;
8385
sector_t sector;
8486

87+
struct bvec_iter saved_bi_iter;
88+
8589
struct rb_node rb_node;
8690
} CRYPTO_MINALIGN_ATTR;
8791

@@ -1370,10 +1374,13 @@ static int crypt_convert_block_aead(struct crypt_config *cc,
13701374
if (r == -EBADMSG) {
13711375
sector_t s = le64_to_cpu(*sector);
13721376

1373-
DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
1374-
ctx->bio_in->bi_bdev, s);
1375-
dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
1376-
ctx->bio_in, s, 0);
1377+
ctx->aead_failed = true;
1378+
if (ctx->aead_recheck) {
1379+
DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
1380+
ctx->bio_in->bi_bdev, s);
1381+
dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
1382+
ctx->bio_in, s, 0);
1383+
}
13771384
}
13781385

13791386
if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
@@ -1757,6 +1764,8 @@ static void crypt_io_init(struct dm_crypt_io *io, struct crypt_config *cc,
17571764
io->base_bio = bio;
17581765
io->sector = sector;
17591766
io->error = 0;
1767+
io->ctx.aead_recheck = false;
1768+
io->ctx.aead_failed = false;
17601769
io->ctx.r.req = NULL;
17611770
io->integrity_metadata = NULL;
17621771
io->integrity_metadata_from_pool = false;
@@ -1768,6 +1777,8 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
17681777
atomic_inc(&io->io_pending);
17691778
}
17701779

1780+
static void kcryptd_queue_read(struct dm_crypt_io *io);
1781+
17711782
/*
17721783
* One of the bios was finished. Check for completion of
17731784
* the whole request and correctly clean up the buffer.
@@ -1781,6 +1792,15 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
17811792
if (!atomic_dec_and_test(&io->io_pending))
17821793
return;
17831794

1795+
if (likely(!io->ctx.aead_recheck) && unlikely(io->ctx.aead_failed) &&
1796+
cc->on_disk_tag_size && bio_data_dir(base_bio) == READ) {
1797+
io->ctx.aead_recheck = true;
1798+
io->ctx.aead_failed = false;
1799+
io->error = 0;
1800+
kcryptd_queue_read(io);
1801+
return;
1802+
}
1803+
17841804
if (io->ctx.r.req)
17851805
crypt_free_req(cc, io->ctx.r.req, base_bio);
17861806

@@ -1816,15 +1836,19 @@ static void crypt_endio(struct bio *clone)
18161836
struct dm_crypt_io *io = clone->bi_private;
18171837
struct crypt_config *cc = io->cc;
18181838
unsigned int rw = bio_data_dir(clone);
1819-
blk_status_t error;
1839+
blk_status_t error = clone->bi_status;
1840+
1841+
if (io->ctx.aead_recheck && !error) {
1842+
kcryptd_queue_crypt(io);
1843+
return;
1844+
}
18201845

18211846
/*
18221847
* free the processed pages
18231848
*/
1824-
if (rw == WRITE)
1849+
if (rw == WRITE || io->ctx.aead_recheck)
18251850
crypt_free_buffer_pages(cc, clone);
18261851

1827-
error = clone->bi_status;
18281852
bio_put(clone);
18291853

18301854
if (rw == READ && !error) {
@@ -1845,6 +1869,22 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
18451869
struct crypt_config *cc = io->cc;
18461870
struct bio *clone;
18471871

1872+
if (io->ctx.aead_recheck) {
1873+
if (!(gfp & __GFP_DIRECT_RECLAIM))
1874+
return 1;
1875+
crypt_inc_pending(io);
1876+
clone = crypt_alloc_buffer(io, io->base_bio->bi_iter.bi_size);
1877+
if (unlikely(!clone)) {
1878+
crypt_dec_pending(io);
1879+
return 1;
1880+
}
1881+
clone->bi_iter.bi_sector = cc->start + io->sector;
1882+
crypt_convert_init(cc, &io->ctx, clone, clone, io->sector);
1883+
io->saved_bi_iter = clone->bi_iter;
1884+
dm_submit_bio_remap(io->base_bio, clone);
1885+
return 0;
1886+
}
1887+
18481888
/*
18491889
* We need the original biovec array in order to decrypt the whole bio
18501890
* data *afterwards* -- thanks to immutable biovecs we don't need to
@@ -2113,6 +2153,14 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
21132153

21142154
static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
21152155
{
2156+
if (io->ctx.aead_recheck) {
2157+
if (!io->error) {
2158+
io->ctx.bio_in->bi_iter = io->saved_bi_iter;
2159+
bio_copy_data(io->base_bio, io->ctx.bio_in);
2160+
}
2161+
crypt_free_buffer_pages(io->cc, io->ctx.bio_in);
2162+
bio_put(io->ctx.bio_in);
2163+
}
21162164
crypt_dec_pending(io);
21172165
}
21182166

@@ -2142,11 +2190,17 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
21422190

21432191
crypt_inc_pending(io);
21442192

2145-
crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio,
2146-
io->sector);
2193+
if (io->ctx.aead_recheck) {
2194+
io->ctx.cc_sector = io->sector + cc->iv_offset;
2195+
r = crypt_convert(cc, &io->ctx,
2196+
test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true);
2197+
} else {
2198+
crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio,
2199+
io->sector);
21472200

2148-
r = crypt_convert(cc, &io->ctx,
2149-
test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true);
2201+
r = crypt_convert(cc, &io->ctx,
2202+
test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true);
2203+
}
21502204
/*
21512205
* Crypto API backlogged the request, because its queue was full
21522206
* and we're in softirq context, so continue from a workqueue
@@ -2188,10 +2242,13 @@ static void kcryptd_async_done(void *data, int error)
21882242
if (error == -EBADMSG) {
21892243
sector_t s = le64_to_cpu(*org_sector_of_dmreq(cc, dmreq));
21902244

2191-
DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
2192-
ctx->bio_in->bi_bdev, s);
2193-
dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
2194-
ctx->bio_in, s, 0);
2245+
ctx->aead_failed = true;
2246+
if (ctx->aead_recheck) {
2247+
DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
2248+
ctx->bio_in->bi_bdev, s);
2249+
dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
2250+
ctx->bio_in, s, 0);
2251+
}
21952252
io->error = BLK_STS_PROTECTION;
21962253
} else if (error < 0)
21972254
io->error = BLK_STS_IOERR;
@@ -3116,7 +3173,7 @@ static int crypt_ctr_optional(struct dm_target *ti, unsigned int argc, char **ar
31163173
sval = strchr(opt_string + strlen("integrity:"), ':') + 1;
31173174
if (!strcasecmp(sval, "aead")) {
31183175
set_bit(CRYPT_MODE_INTEGRITY_AEAD, &cc->cipher_flags);
3119-
} else if (strcasecmp(sval, "none")) {
3176+
} else if (strcasecmp(sval, "none")) {
31203177
ti->error = "Unknown integrity profile";
31213178
return -EINVAL;
31223179
}

0 commit comments

Comments
 (0)