Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Mikulas Patocka and committed by
Mike Snitzer
42e15d12 50c70240

+73 -16
+73 -16
drivers/md/dm-crypt.c
··· 62 62 struct skcipher_request *req; 63 63 struct aead_request *req_aead; 64 64 } r; 65 + bool aead_recheck; 66 + bool aead_failed; 65 67 66 68 }; 67 69 ··· 83 81 atomic_t io_pending; 84 82 blk_status_t error; 85 83 sector_t sector; 84 + 85 + struct bvec_iter saved_bi_iter; 86 86 87 87 struct rb_node rb_node; 88 88 } CRYPTO_MINALIGN_ATTR; ··· 1374 1370 if (r == -EBADMSG) { 1375 1371 sector_t s = le64_to_cpu(*sector); 1376 1372 1377 - DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu", 1378 - ctx->bio_in->bi_bdev, s); 1379 - dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead", 1380 - ctx->bio_in, s, 0); 1373 + ctx->aead_failed = true; 1374 + if (ctx->aead_recheck) { 1375 + DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu", 1376 + ctx->bio_in->bi_bdev, s); 1377 + dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead", 1378 + ctx->bio_in, s, 0); 1379 + } 1381 1380 } 1382 1381 1383 1382 if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post) ··· 1764 1757 io->base_bio = bio; 1765 1758 io->sector = sector; 1766 1759 io->error = 0; 1760 + io->ctx.aead_recheck = false; 1761 + io->ctx.aead_failed = false; 1767 1762 io->ctx.r.req = NULL; 1768 1763 io->integrity_metadata = NULL; 1769 1764 io->integrity_metadata_from_pool = false; ··· 1776 1767 { 1777 1768 atomic_inc(&io->io_pending); 1778 1769 } 1770 + 1771 + static void kcryptd_queue_read(struct dm_crypt_io *io); 1779 1772 1780 1773 /* 1781 1774 * One of the bios was finished. Check for completion of ··· 1791 1780 1792 1781 if (!atomic_dec_and_test(&io->io_pending)) 1793 1782 return; 1783 + 1784 + if (likely(!io->ctx.aead_recheck) && unlikely(io->ctx.aead_failed) && 1785 + cc->on_disk_tag_size && bio_data_dir(base_bio) == READ) { 1786 + io->ctx.aead_recheck = true; 1787 + io->ctx.aead_failed = false; 1788 + io->error = 0; 1789 + kcryptd_queue_read(io); 1790 + return; 1791 + } 1794 1792 1795 1793 if (io->ctx.r.req) 1796 1794 crypt_free_req(cc, io->ctx.r.req, base_bio); ··· 1836 1816 struct dm_crypt_io *io = clone->bi_private; 1837 1817 struct crypt_config *cc = io->cc; 1838 1818 unsigned int rw = bio_data_dir(clone); 1839 - blk_status_t error; 1819 + blk_status_t error = clone->bi_status; 1820 + 1821 + if (io->ctx.aead_recheck && !error) { 1822 + kcryptd_queue_crypt(io); 1823 + return; 1824 + } 1840 1825 1841 1826 /* 1842 1827 * free the processed pages 1843 1828 */ 1844 - if (rw == WRITE) 1829 + if (rw == WRITE || io->ctx.aead_recheck) 1845 1830 crypt_free_buffer_pages(cc, clone); 1846 1831 1847 - error = clone->bi_status; 1848 1832 bio_put(clone); 1849 1833 1850 1834 if (rw == READ && !error) { ··· 1868 1844 { 1869 1845 struct crypt_config *cc = io->cc; 1870 1846 struct bio *clone; 1847 + 1848 + if (io->ctx.aead_recheck) { 1849 + if (!(gfp & __GFP_DIRECT_RECLAIM)) 1850 + return 1; 1851 + crypt_inc_pending(io); 1852 + clone = crypt_alloc_buffer(io, io->base_bio->bi_iter.bi_size); 1853 + if (unlikely(!clone)) { 1854 + crypt_dec_pending(io); 1855 + return 1; 1856 + } 1857 + clone->bi_iter.bi_sector = cc->start + io->sector; 1858 + crypt_convert_init(cc, &io->ctx, clone, clone, io->sector); 1859 + io->saved_bi_iter = clone->bi_iter; 1860 + dm_submit_bio_remap(io->base_bio, clone); 1861 + return 0; 1862 + } 1871 1863 1872 1864 /* 1873 1865 * We need the original biovec array in order to decrypt the whole bio ··· 2153 2113 2154 2114 static void kcryptd_crypt_read_done(struct dm_crypt_io *io) 2155 2115 { 2116 + if (io->ctx.aead_recheck) { 2117 + if (!io->error) { 2118 + io->ctx.bio_in->bi_iter = io->saved_bi_iter; 2119 + bio_copy_data(io->base_bio, io->ctx.bio_in); 2120 + } 2121 + crypt_free_buffer_pages(io->cc, io->ctx.bio_in); 2122 + bio_put(io->ctx.bio_in); 2123 + } 2156 2124 crypt_dec_pending(io); 2157 2125 } 2158 2126 ··· 2190 2142 2191 2143 crypt_inc_pending(io); 2192 2144 2193 - crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio, 2194 - io->sector); 2145 + if (io->ctx.aead_recheck) { 2146 + io->ctx.cc_sector = io->sector + cc->iv_offset; 2147 + r = crypt_convert(cc, &io->ctx, 2148 + test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true); 2149 + } else { 2150 + crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio, 2151 + io->sector); 2195 2152 2196 - r = crypt_convert(cc, &io->ctx, 2197 - test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true); 2153 + r = crypt_convert(cc, &io->ctx, 2154 + test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true); 2155 + } 2198 2156 /* 2199 2157 * Crypto API backlogged the request, because its queue was full 2200 2158 * and we're in softirq context, so continue from a workqueue ··· 2242 2188 if (error == -EBADMSG) { 2243 2189 sector_t s = le64_to_cpu(*org_sector_of_dmreq(cc, dmreq)); 2244 2190 2245 - DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu", 2246 - ctx->bio_in->bi_bdev, s); 2247 - dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead", 2248 - ctx->bio_in, s, 0); 2191 + ctx->aead_failed = true; 2192 + if (ctx->aead_recheck) { 2193 + DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu", 2194 + ctx->bio_in->bi_bdev, s); 2195 + dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead", 2196 + ctx->bio_in, s, 0); 2197 + } 2249 2198 io->error = BLK_STS_PROTECTION; 2250 2199 } else if (error < 0) 2251 2200 io->error = BLK_STS_IOERR; ··· 3173 3116 sval = strchr(opt_string + strlen("integrity:"), ':') + 1; 3174 3117 if (!strcasecmp(sval, "aead")) { 3175 3118 set_bit(CRYPT_MODE_INTEGRITY_AEAD, &cc->cipher_flags); 3176 - } else if (strcasecmp(sval, "none")) { 3119 + } else if (strcasecmp(sval, "none")) { 3177 3120 ti->error = "Unknown integrity profile"; 3178 3121 return -EINVAL; 3179 3122 }