diff options
author | Ondrej Mosnacek <omosnace@redhat.com> | 2018-08-22 02:26:31 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-08-25 07:50:43 -0400 |
commit | 0522236d4f9c5ab2e79889cb020d1acbe5da416e (patch) | |
tree | 3458805e8f6ed1e886d84706dd595b6eea6f933e | |
parent | c2b24c36e0a30ebd8fc7d068da7f0451f2c05c76 (diff) |
crypto: vmx - Fix sleep-in-atomic bugs
This patch fixes sleep-in-atomic bugs in AES-CBC and AES-XTS VMX
implementations. The problem is that the blkcipher_* functions should
not be called in atomic context.
The bugs can be reproduced via the AF_ALG interface by trying to
encrypt/decrypt sufficiently large buffers (at least 64 KiB) using the
VMX implementations of 'cbc(aes)' or 'xts(aes)'. Such operations then
trigger BUG in crypto_yield():
[ 891.863680] BUG: sleeping function called from invalid context at include/crypto/algapi.h:424
[ 891.864622] in_atomic(): 1, irqs_disabled(): 0, pid: 12347, name: kcapi-enc
[ 891.864739] 1 lock held by kcapi-enc/12347:
[ 891.864811] #0: 00000000f5d42c46 (sk_lock-AF_ALG){+.+.}, at: skcipher_recvmsg+0x50/0x530
[ 891.865076] CPU: 5 PID: 12347 Comm: kcapi-enc Not tainted 4.19.0-0.rc0.git3.1.fc30.ppc64le #1
[ 891.865251] Call Trace:
[ 891.865340] [c0000003387578c0] [c000000000d67ea4] dump_stack+0xe8/0x164 (unreliable)
[ 891.865511] [c000000338757910] [c000000000172a58] ___might_sleep+0x2f8/0x310
[ 891.865679] [c000000338757990] [c0000000006bff74] blkcipher_walk_done+0x374/0x4a0
[ 891.865825] [c0000003387579e0] [d000000007e73e70] p8_aes_cbc_encrypt+0x1c8/0x260 [vmx_crypto]
[ 891.865993] [c000000338757ad0] [c0000000006c0ee0] skcipher_encrypt_blkcipher+0x60/0x80
[ 891.866128] [c000000338757b10] [c0000000006ec504] skcipher_recvmsg+0x424/0x530
[ 891.866283] [c000000338757bd0] [c000000000b00654] sock_recvmsg+0x74/0xa0
[ 891.866403] [c000000338757c10] [c000000000b00f64] ___sys_recvmsg+0xf4/0x2f0
[ 891.866515] [c000000338757d90] [c000000000b02bb8] __sys_recvmsg+0x68/0xe0
[ 891.866631] [c000000338757e30] [c00000000000bbe4] system_call+0x5c/0x70
Fixes: 8c755ace357c ("crypto: vmx - Adding CBC routines for VMX module")
Fixes: c07f5d3da643 ("crypto: vmx - Adding support for XTS")
Cc: stable@vger.kernel.org
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | drivers/crypto/vmx/aes_cbc.c | 30 | ||||
-rw-r--r-- | drivers/crypto/vmx/aes_xts.c | 21 |
2 files changed, 28 insertions, 23 deletions
diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 5285ece4f33a..b71895871be3 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c | |||
@@ -107,24 +107,23 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc, | |||
107 | ret = crypto_skcipher_encrypt(req); | 107 | ret = crypto_skcipher_encrypt(req); |
108 | skcipher_request_zero(req); | 108 | skcipher_request_zero(req); |
109 | } else { | 109 | } else { |
110 | preempt_disable(); | ||
111 | pagefault_disable(); | ||
112 | enable_kernel_vsx(); | ||
113 | |||
114 | blkcipher_walk_init(&walk, dst, src, nbytes); | 110 | blkcipher_walk_init(&walk, dst, src, nbytes); |
115 | ret = blkcipher_walk_virt(desc, &walk); | 111 | ret = blkcipher_walk_virt(desc, &walk); |
116 | while ((nbytes = walk.nbytes)) { | 112 | while ((nbytes = walk.nbytes)) { |
113 | preempt_disable(); | ||
114 | pagefault_disable(); | ||
115 | enable_kernel_vsx(); | ||
117 | aes_p8_cbc_encrypt(walk.src.virt.addr, | 116 | aes_p8_cbc_encrypt(walk.src.virt.addr, |
118 | walk.dst.virt.addr, | 117 | walk.dst.virt.addr, |
119 | nbytes & AES_BLOCK_MASK, | 118 | nbytes & AES_BLOCK_MASK, |
120 | &ctx->enc_key, walk.iv, 1); | 119 | &ctx->enc_key, walk.iv, 1); |
120 | disable_kernel_vsx(); | ||
121 | pagefault_enable(); | ||
122 | preempt_enable(); | ||
123 | |||
121 | nbytes &= AES_BLOCK_SIZE - 1; | 124 | nbytes &= AES_BLOCK_SIZE - 1; |
122 | ret = blkcipher_walk_done(desc, &walk, nbytes); | 125 | ret = blkcipher_walk_done(desc, &walk, nbytes); |
123 | } | 126 | } |
124 | |||
125 | disable_kernel_vsx(); | ||
126 | pagefault_enable(); | ||
127 | preempt_enable(); | ||
128 | } | 127 | } |
129 | 128 | ||
130 | return ret; | 129 | return ret; |
@@ -147,24 +146,23 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc, | |||
147 | ret = crypto_skcipher_decrypt(req); | 146 | ret = crypto_skcipher_decrypt(req); |
148 | skcipher_request_zero(req); | 147 | skcipher_request_zero(req); |
149 | } else { | 148 | } else { |
150 | preempt_disable(); | ||
151 | pagefault_disable(); | ||
152 | enable_kernel_vsx(); | ||
153 | |||
154 | blkcipher_walk_init(&walk, dst, src, nbytes); | 149 | blkcipher_walk_init(&walk, dst, src, nbytes); |
155 | ret = blkcipher_walk_virt(desc, &walk); | 150 | ret = blkcipher_walk_virt(desc, &walk); |
156 | while ((nbytes = walk.nbytes)) { | 151 | while ((nbytes = walk.nbytes)) { |
152 | preempt_disable(); | ||
153 | pagefault_disable(); | ||
154 | enable_kernel_vsx(); | ||
157 | aes_p8_cbc_encrypt(walk.src.virt.addr, | 155 | aes_p8_cbc_encrypt(walk.src.virt.addr, |
158 | walk.dst.virt.addr, | 156 | walk.dst.virt.addr, |
159 | nbytes & AES_BLOCK_MASK, | 157 | nbytes & AES_BLOCK_MASK, |
160 | &ctx->dec_key, walk.iv, 0); | 158 | &ctx->dec_key, walk.iv, 0); |
159 | disable_kernel_vsx(); | ||
160 | pagefault_enable(); | ||
161 | preempt_enable(); | ||
162 | |||
161 | nbytes &= AES_BLOCK_SIZE - 1; | 163 | nbytes &= AES_BLOCK_SIZE - 1; |
162 | ret = blkcipher_walk_done(desc, &walk, nbytes); | 164 | ret = blkcipher_walk_done(desc, &walk, nbytes); |
163 | } | 165 | } |
164 | |||
165 | disable_kernel_vsx(); | ||
166 | pagefault_enable(); | ||
167 | preempt_enable(); | ||
168 | } | 166 | } |
169 | 167 | ||
170 | return ret; | 168 | return ret; |
diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index 8bd9aff0f55f..e9954a7d4694 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c | |||
@@ -116,32 +116,39 @@ static int p8_aes_xts_crypt(struct blkcipher_desc *desc, | |||
116 | ret = enc? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); | 116 | ret = enc? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); |
117 | skcipher_request_zero(req); | 117 | skcipher_request_zero(req); |
118 | } else { | 118 | } else { |
119 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
120 | |||
121 | ret = blkcipher_walk_virt(desc, &walk); | ||
122 | |||
119 | preempt_disable(); | 123 | preempt_disable(); |
120 | pagefault_disable(); | 124 | pagefault_disable(); |
121 | enable_kernel_vsx(); | 125 | enable_kernel_vsx(); |
122 | 126 | ||
123 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
124 | |||
125 | ret = blkcipher_walk_virt(desc, &walk); | ||
126 | iv = walk.iv; | 127 | iv = walk.iv; |
127 | memset(tweak, 0, AES_BLOCK_SIZE); | 128 | memset(tweak, 0, AES_BLOCK_SIZE); |
128 | aes_p8_encrypt(iv, tweak, &ctx->tweak_key); | 129 | aes_p8_encrypt(iv, tweak, &ctx->tweak_key); |
129 | 130 | ||
131 | disable_kernel_vsx(); | ||
132 | pagefault_enable(); | ||
133 | preempt_enable(); | ||
134 | |||
130 | while ((nbytes = walk.nbytes)) { | 135 | while ((nbytes = walk.nbytes)) { |
136 | preempt_disable(); | ||
137 | pagefault_disable(); | ||
138 | enable_kernel_vsx(); | ||
131 | if (enc) | 139 | if (enc) |
132 | aes_p8_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr, | 140 | aes_p8_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr, |
133 | nbytes & AES_BLOCK_MASK, &ctx->enc_key, NULL, tweak); | 141 | nbytes & AES_BLOCK_MASK, &ctx->enc_key, NULL, tweak); |
134 | else | 142 | else |
135 | aes_p8_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr, | 143 | aes_p8_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr, |
136 | nbytes & AES_BLOCK_MASK, &ctx->dec_key, NULL, tweak); | 144 | nbytes & AES_BLOCK_MASK, &ctx->dec_key, NULL, tweak); |
145 | disable_kernel_vsx(); | ||
146 | pagefault_enable(); | ||
147 | preempt_enable(); | ||
137 | 148 | ||
138 | nbytes &= AES_BLOCK_SIZE - 1; | 149 | nbytes &= AES_BLOCK_SIZE - 1; |
139 | ret = blkcipher_walk_done(desc, &walk, nbytes); | 150 | ret = blkcipher_walk_done(desc, &walk, nbytes); |
140 | } | 151 | } |
141 | |||
142 | disable_kernel_vsx(); | ||
143 | pagefault_enable(); | ||
144 | preempt_enable(); | ||
145 | } | 152 | } |
146 | return ret; | 153 | return ret; |
147 | } | 154 | } |