Fix the following problem, which can occur even on UP systems: 1. one process starts encryption, but is scheduled out partway through. 2. second process starts doing encryption with the same crypto_tfm; but it's using some messed-up tfm now (e.g. iv is set wrong at a minimum). Note that the crypto code has schedule()s after each block encrypt. The 2.4 crypto code had an atomicapi flag you could set to help here, but the 2.5 code doesn't (and we'd have a problem like this on SMP systems anyway). However, the 2.5 code does check in_softirq() before scheduling, and it seems we can make in_softirq() true by doing a spin_lock_bh(), so that's what we do'll do here; we add these spinlocks around every crypto operation. linux/sunrpc/gss_krb5.h | 17 +++++++++++------ sunrpc/auth_gss/gss_krb5_crypto.c | 11 +++++++++-- sunrpc/auth_gss/gss_krb5_mech.c | 21 +++++++++++---------- sunrpc/auth_gss/gss_krb5_seal.c | 8 ++++---- sunrpc/auth_gss/gss_krb5_seqnum.c | 4 ++-- sunrpc/auth_gss/gss_krb5_unseal.c | 8 ++++---- 6 files changed, 41 insertions(+), 28 deletions(-) diff -puN include/linux/sunrpc/gss_krb5.h~linux-2.5.63-gss-krb5-crypto-locking include/linux/sunrpc/gss_krb5.h --- linux-2.5.63-playground/include/linux/sunrpc/gss_krb5.h~linux-2.5.63-gss-krb5-crypto-locking 2003-03-05 00:31:39.000000000 -0500 +++ linux-2.5.63-playground-bfields/include/linux/sunrpc/gss_krb5.h 2003-03-05 15:28:37.000000000 -0500 @@ -40,14 +40,19 @@ #include #include +struct atomic_tfm { + struct crypto_tfm *tfm; + spinlock_t lock; +}; + struct krb5_ctx { int initiate; /* 1 = initiating, 0 = accepting */ int seed_init; unsigned char seed[16]; int signalg; int sealalg; - struct crypto_tfm *enc; - struct crypto_tfm *seq; + struct atomic_tfm enc; + struct atomic_tfm seq; s32 endtime; u32 seq_send; u32 seq_recv; @@ -142,19 +147,19 @@ krb5_read_token(struct krb5_ctx *context int *qop_state, int toktype); u32 -krb5_encrypt(struct crypto_tfm * key, +krb5_encrypt(struct atomic_tfm * key, void *iv, void *in, void *out, int length); u32 -krb5_decrypt(struct crypto_tfm * key, +krb5_decrypt(struct atomic_tfm * key, void *iv, void *in, void *out, int length); s32 -krb5_make_seq_num(struct crypto_tfm * key, +krb5_make_seq_num(struct atomic_tfm * key, int direction, s32 seqnum, unsigned char *cksum, unsigned char *buf); s32 -krb5_get_seq_num(struct crypto_tfm * key, +krb5_get_seq_num(struct atomic_tfm * key, unsigned char *cksum, unsigned char *buf, int *direction, s32 * seqnum); diff -puN net/sunrpc/auth_gss/gss_krb5_crypto.c~linux-2.5.63-gss-krb5-crypto-locking net/sunrpc/auth_gss/gss_krb5_crypto.c --- linux-2.5.63-playground/net/sunrpc/auth_gss/gss_krb5_crypto.c~linux-2.5.63-gss-krb5-crypto-locking 2003-03-05 00:31:39.000000000 -0500 +++ linux-2.5.63-playground-bfields/net/sunrpc/auth_gss/gss_krb5_crypto.c 2003-03-05 15:28:37.000000000 -0500 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,7 @@ u32 krb5_encrypt( - struct crypto_tfm *tfm, + struct atomic_tfm *atfm, void * iv, void * in, void * out, @@ -56,6 +57,7 @@ krb5_encrypt( u32 ret = -EINVAL; struct scatterlist sg[1]; u8 local_iv[16] = {0}; + struct crypto_tfm *tfm = atfm->tfm; dprintk("RPC: gss_k5encrypt: TOP in %p out %p\nin data:\n", out, in); print_hexl((u32 *)in, length, 0); @@ -71,6 +73,7 @@ krb5_encrypt( if (iv) memcpy(local_iv, iv, crypto_tfm_alg_ivsize(tfm)); + spin_lock_bh(&atfm->lock); crypto_cipher_set_iv(tfm, local_iv, crypto_tfm_alg_ivsize(tfm)); memcpy(out, in, length); @@ -79,6 +82,7 @@ krb5_encrypt( sg[0].length = length; ret = crypto_cipher_encrypt(tfm, sg, sg, length); + spin_unlock_bh(&atfm->lock); out: dprintk("gss_k5encrypt returns %d\n",ret); @@ -87,7 +91,7 @@ out: u32 krb5_decrypt( - struct crypto_tfm *tfm, + struct atomic_tfm *atfm, void * iv, void * in, void * out, @@ -96,6 +100,7 @@ krb5_decrypt( u32 ret = -EINVAL; struct scatterlist sg[1]; u8 local_iv[16] = {0}; + struct crypto_tfm *tfm = atfm->tfm; dprintk("RPC: gss_k5decrypt: TOP in %p out %p\nin data:\n", in, out); print_hexl((u32 *)in,length,0); @@ -110,6 +115,7 @@ krb5_decrypt( } if (iv) memcpy(local_iv,iv, crypto_tfm_alg_ivsize(tfm)); + spin_lock_bh(&atfm->lock); crypto_cipher_set_iv(tfm, local_iv, crypto_tfm_alg_blocksize(tfm)); memcpy(out, in, length); @@ -118,6 +124,7 @@ krb5_decrypt( sg[0].length = length; ret = crypto_cipher_decrypt(tfm, sg, sg, length); + spin_unlock_bh(&atfm->lock); out: dprintk("gss_k5decrypt returns %d\n",ret); diff -puN net/sunrpc/auth_gss/gss_krb5_mech.c~linux-2.5.63-gss-krb5-crypto-locking net/sunrpc/auth_gss/gss_krb5_mech.c --- linux-2.5.63-playground/net/sunrpc/auth_gss/gss_krb5_mech.c~linux-2.5.63-gss-krb5-crypto-locking 2003-03-05 00:31:39.000000000 -0500 +++ linux-2.5.63-playground-bfields/net/sunrpc/auth_gss/gss_krb5_mech.c 2003-03-05 15:28:37.000000000 -0500 @@ -81,7 +81,7 @@ get_netobj(char **ptr, const char *end, } static inline int -get_key(char **p, char *end, struct crypto_tfm **res) +get_key(char **p, char *end, struct atomic_tfm *res) { struct xdr_netobj key; int alg, alg_mode; @@ -101,16 +101,17 @@ get_key(char **p, char *end, struct cryp dprintk("RPC: get_key: unsupported algorithm %d", alg); goto out_err_free_key; } - if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) + if (!(res->tfm = crypto_alloc_tfm(alg_name, alg_mode))) goto out_err_free_key; - if (crypto_cipher_setkey(*res, key.data, key.len)) + if (crypto_cipher_setkey(res->tfm, key.data, key.len)) goto out_err_free_tfm; + spin_lock_init(&res->lock); kfree(key.data); return 0; out_err_free_tfm: - crypto_free_tfm(*res); + crypto_free_tfm(res->tfm); out_err_free_key: kfree(key.data); out_err: @@ -157,9 +158,9 @@ gss_import_sec_context_kerberos(struct x return 0; out_err_free_key2: - crypto_free_tfm(ctx->seq); + crypto_free_tfm(ctx->seq.tfm); out_err_free_key1: - crypto_free_tfm(ctx->enc); + crypto_free_tfm(ctx->enc.tfm); out_err_free_mech: kfree(ctx->mech_used.data); out_err_free_ctx: @@ -172,10 +173,10 @@ void gss_delete_sec_context_kerberos(void *internal_ctx) { struct krb5_ctx *kctx = internal_ctx; - if (kctx->seq) - crypto_free_tfm(kctx->seq); - if (kctx->enc) - crypto_free_tfm(kctx->enc); + if (kctx->seq.tfm) + crypto_free_tfm(kctx->seq.tfm); + if (kctx->enc.tfm) + crypto_free_tfm(kctx->enc.tfm); if (kctx->mech_used.data) kfree(kctx->mech_used.data); kfree(kctx); diff -puN net/sunrpc/auth_gss/gss_krb5_seal.c~linux-2.5.63-gss-krb5-crypto-locking net/sunrpc/auth_gss/gss_krb5_seal.c --- linux-2.5.63-playground/net/sunrpc/auth_gss/gss_krb5_seal.c~linux-2.5.63-gss-krb5-crypto-locking 2003-03-05 00:31:39.000000000 -0500 +++ linux-2.5.63-playground-bfields/net/sunrpc/auth_gss/gss_krb5_seal.c 2003-03-05 15:28:37.000000000 -0500 @@ -136,7 +136,7 @@ krb5_make_token(struct krb5_ctx *ctx, in } if (toktype == KG_TOK_WRAP_MSG) { - blocksize = crypto_tfm_alg_blocksize(ctx->enc); + blocksize = crypto_tfm_alg_blocksize(ctx->enc.tfm); tmsglen = blocksize + text->len + gss_krb5_padding(blocksize, blocksize + text->len); } else { @@ -171,7 +171,7 @@ krb5_make_token(struct krb5_ctx *ctx, in tmsglen, &md5cksum)) goto out_err; - if (krb5_encrypt(ctx->enc, NULL, msg_start, msg_start, + if (krb5_encrypt(&ctx->enc, NULL, msg_start, msg_start, tmsglen)) goto out_err; @@ -183,7 +183,7 @@ krb5_make_token(struct krb5_ctx *ctx, in switch (ctx->signalg) { case SGN_ALG_DES_MAC_MD5: - if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, + if (krb5_encrypt(&ctx->seq, NULL, md5cksum.data, md5cksum.data, md5cksum.len)) goto out_err; memcpy(krb5_hdr + 16, @@ -198,7 +198,7 @@ krb5_make_token(struct krb5_ctx *ctx, in kfree(md5cksum.data); - if ((krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, + if ((krb5_make_seq_num(&ctx->seq, ctx->initiate ? 0 : 0xff, ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))) goto out_err; diff -puN net/sunrpc/auth_gss/gss_krb5_seqnum.c~linux-2.5.63-gss-krb5-crypto-locking net/sunrpc/auth_gss/gss_krb5_seqnum.c --- linux-2.5.63-playground/net/sunrpc/auth_gss/gss_krb5_seqnum.c~linux-2.5.63-gss-krb5-crypto-locking 2003-03-05 00:31:39.000000000 -0500 +++ linux-2.5.63-playground-bfields/net/sunrpc/auth_gss/gss_krb5_seqnum.c 2003-03-05 00:31:39.000000000 -0500 @@ -41,7 +41,7 @@ #endif s32 -krb5_make_seq_num(struct crypto_tfm *key, +krb5_make_seq_num(struct atomic_tfm *key, int direction, s32 seqnum, unsigned char *cksum, unsigned char *buf) @@ -62,7 +62,7 @@ krb5_make_seq_num(struct crypto_tfm *key } s32 -krb5_get_seq_num(struct crypto_tfm *key, +krb5_get_seq_num(struct atomic_tfm *key, unsigned char *cksum, unsigned char *buf, int *direction, s32 * seqnum) diff -puN net/sunrpc/auth_gss/gss_krb5_unseal.c~linux-2.5.63-gss-krb5-crypto-locking net/sunrpc/auth_gss/gss_krb5_unseal.c --- linux-2.5.63-playground/net/sunrpc/auth_gss/gss_krb5_unseal.c~linux-2.5.63-gss-krb5-crypto-locking 2003-03-05 00:31:39.000000000 -0500 +++ linux-2.5.63-playground-bfields/net/sunrpc/auth_gss/gss_krb5_unseal.c 2003-03-05 15:28:37.000000000 -0500 @@ -162,7 +162,7 @@ krb5_read_token(struct krb5_ctx *ctx, if (plain == NULL) goto out; - code = krb5_decrypt(ctx->enc, NULL, + code = krb5_decrypt(&ctx->enc, NULL, ptr + 14 + cksum_len, plain, tmsglen); if (code) @@ -170,7 +170,7 @@ krb5_read_token(struct krb5_ctx *ctx, plainlen = tmsglen; - conflen = crypto_tfm_alg_blocksize(ctx->enc); + conflen = crypto_tfm_alg_blocksize(ctx->enc.tfm); token.len = tmsglen - conflen - plain[tmsglen - 1]; if (token.len) { @@ -233,7 +233,7 @@ krb5_read_token(struct krb5_ctx *ctx, if (code) goto out; - code = krb5_encrypt(ctx->seq, NULL, md5cksum.data, + code = krb5_encrypt(&ctx->seq, NULL, md5cksum.data, md5cksum.data, 16); if (code) goto out; @@ -287,7 +287,7 @@ krb5_read_token(struct krb5_ctx *ctx, /* do sequencing checks */ ret = GSS_S_BAD_SIG; - if ((code = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction, + if ((code = krb5_get_seq_num(&ctx->seq, ptr + 14, ptr + 6, &direction, &seqnum))) goto out; _