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.

crypto: authenc - Correctly pass EINPROGRESS back up to the caller

When authenc is invoked with MAY_BACKLOG, it needs to pass EINPROGRESS
notifications back up to the caller when the underlying algorithm
returns EBUSY synchronously.

However, if the EBUSY comes from the second part of an authenc call,
i.e., it is asynchronous, both the EBUSY and the subsequent EINPROGRESS
notification must not be passed to the caller.

Implement this by passing a mask to the function that starts the
second half of authenc and using it to determine whether EBUSY
and EINPROGRESS should be passed to the caller.

This was a deficiency in the original implementation of authenc
because it was not expected to be used with MAY_BACKLOG.

Reported-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reported-by: Mikulas Patocka <mpatocka@redhat.com>
Fixes: 180ce7e81030 ("crypto: authenc - Add EINPROGRESS check")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

+50 -25
+50 -25
crypto/authenc.c
··· 37 37 38 38 static void authenc_request_complete(struct aead_request *req, int err) 39 39 { 40 - if (err != -EINPROGRESS) 40 + if (err != -EINPROGRESS && err != -EBUSY) 41 41 aead_request_complete(req, err); 42 42 } 43 43 ··· 107 107 return err; 108 108 } 109 109 110 - static void authenc_geniv_ahash_done(void *data, int err) 110 + static void authenc_geniv_ahash_finish(struct aead_request *req) 111 111 { 112 - struct aead_request *req = data; 113 112 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 114 113 struct aead_instance *inst = aead_alg_instance(authenc); 115 114 struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); 116 115 struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); 117 116 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 118 117 119 - if (err) 120 - goto out; 121 - 122 118 scatterwalk_map_and_copy(ahreq->result, req->dst, 123 119 req->assoclen + req->cryptlen, 124 120 crypto_aead_authsize(authenc), 1); 121 + } 125 122 126 - out: 123 + static void authenc_geniv_ahash_done(void *data, int err) 124 + { 125 + struct aead_request *req = data; 126 + 127 + if (!err) 128 + authenc_geniv_ahash_finish(req); 127 129 aead_request_complete(req, err); 128 130 } 129 131 130 - static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags) 132 + /* 133 + * Used when the ahash request was invoked in the async callback context 134 + * of the previous skcipher request. Eat any EINPROGRESS notifications. 135 + */ 136 + static void authenc_geniv_ahash_done2(void *data, int err) 137 + { 138 + struct aead_request *req = data; 139 + 140 + if (!err) 141 + authenc_geniv_ahash_finish(req); 142 + authenc_request_complete(req, err); 143 + } 144 + 145 + static int crypto_authenc_genicv(struct aead_request *req, unsigned int mask) 131 146 { 132 147 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 133 148 struct aead_instance *inst = aead_alg_instance(authenc); ··· 151 136 struct crypto_ahash *auth = ctx->auth; 152 137 struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); 153 138 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 139 + unsigned int flags = aead_request_flags(req) & ~mask; 154 140 u8 *hash = areq_ctx->tail; 155 141 int err; 156 142 ··· 159 143 ahash_request_set_crypt(ahreq, req->dst, hash, 160 144 req->assoclen + req->cryptlen); 161 145 ahash_request_set_callback(ahreq, flags, 162 - authenc_geniv_ahash_done, req); 146 + mask ? authenc_geniv_ahash_done2 : 147 + authenc_geniv_ahash_done, req); 163 148 164 149 err = crypto_ahash_digest(ahreq); 165 150 if (err) ··· 176 159 { 177 160 struct aead_request *areq = data; 178 161 179 - if (err) 180 - goto out; 181 - 182 - err = crypto_authenc_genicv(areq, 0); 183 - 184 - out: 162 + if (err) { 163 + aead_request_complete(areq, err); 164 + return; 165 + } 166 + err = crypto_authenc_genicv(areq, CRYPTO_TFM_REQ_MAY_SLEEP); 185 167 authenc_request_complete(areq, err); 186 168 } 187 169 ··· 215 199 if (err) 216 200 return err; 217 201 218 - return crypto_authenc_genicv(req, aead_request_flags(req)); 202 + return crypto_authenc_genicv(req, 0); 203 + } 204 + 205 + static void authenc_decrypt_tail_done(void *data, int err) 206 + { 207 + struct aead_request *req = data; 208 + 209 + authenc_request_complete(req, err); 219 210 } 220 211 221 212 static int crypto_authenc_decrypt_tail(struct aead_request *req, 222 - unsigned int flags) 213 + unsigned int mask) 223 214 { 224 215 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 225 216 struct aead_instance *inst = aead_alg_instance(authenc); ··· 237 214 struct skcipher_request *skreq = (void *)(areq_ctx->tail + 238 215 ictx->reqoff); 239 216 unsigned int authsize = crypto_aead_authsize(authenc); 217 + unsigned int flags = aead_request_flags(req) & ~mask; 240 218 u8 *ihash = ahreq->result + authsize; 241 219 struct scatterlist *src, *dst; 242 220 ··· 254 230 255 231 skcipher_request_set_tfm(skreq, ctx->enc); 256 232 skcipher_request_set_callback(skreq, flags, 257 - req->base.complete, req->base.data); 233 + mask ? authenc_decrypt_tail_done : 234 + req->base.complete, 235 + mask ? req : req->base.data); 258 236 skcipher_request_set_crypt(skreq, src, dst, 259 237 req->cryptlen - authsize, req->iv); 260 238 ··· 267 241 { 268 242 struct aead_request *req = data; 269 243 270 - if (err) 271 - goto out; 272 - 273 - err = crypto_authenc_decrypt_tail(req, 0); 274 - 275 - out: 244 + if (err) { 245 + aead_request_complete(req, err); 246 + return; 247 + } 248 + err = crypto_authenc_decrypt_tail(req, CRYPTO_TFM_REQ_MAY_SLEEP); 276 249 authenc_request_complete(req, err); 277 250 } 278 251 ··· 298 273 if (err) 299 274 return err; 300 275 301 - return crypto_authenc_decrypt_tail(req, aead_request_flags(req)); 276 + return crypto_authenc_decrypt_tail(req, 0); 302 277 } 303 278 304 279 static int crypto_authenc_init_tfm(struct crypto_aead *tfm)