Certain hardware crypto engines need input data to be correctly aligned. Due to copyless operation, data alignment has to be done in userspace. To assist in that, find out the smallest possible alignment boundary upon session creation, depending on the actual cipher/hash mode(s) being selected (and the automatically chosen crypto backend, of course).
Since now the information is present internally, check directly used (zero-copy) userspace buffers for correct alignment. Handling of temporary, internal buffers is unclear for now. Maybe one should align them to a high value (e.g. 64 bytes) to be sure. Allocating everything dynamically instead is probably not a good alternative. The only buffers userspace applications have to align are the 'src' and 'dst' fields of struct crypt_op. All other userspace buffers are copied internally, since their small size doesn't justify the overhead of mapping userspace pages for them. --- cryptodev.h | 2 ++ cryptodev_cipher.c | 2 ++ cryptodev_int.h | 4 ++++ cryptodev_main.c | 18 +++++++++++++++++- 4 files changed, 25 insertions(+), 1 deletions(-) diff --git a/cryptodev.h b/cryptodev.h index e16d30a..f367262 100644 --- a/cryptodev.h +++ b/cryptodev.h @@ -81,6 +81,8 @@ struct session_op { __u8 __user *mackey; __u32 ses; /* session identifier */ + + __u16 alignmask; /* alignment constraints */ }; #define COP_ENCRYPT 0 diff --git a/cryptodev_cipher.c b/cryptodev_cipher.c index 0dd3fba..0bce1b6 100644 --- a/cryptodev_cipher.c +++ b/cryptodev_cipher.c @@ -94,6 +94,7 @@ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, out->blocksize = crypto_ablkcipher_blocksize(out->async.s); out->ivsize = crypto_ablkcipher_ivsize(out->async.s); + out->alignmask = crypto_ablkcipher_alignmask(out->async.s); out->async.result = kmalloc(sizeof(*out->async.result), GFP_KERNEL); if (unlikely(!out->async.result)) { @@ -225,6 +226,7 @@ int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, } hdata->digestsize = crypto_ahash_digestsize(hdata->async.s); + hdata->alignmask = crypto_ahash_alignmask(hdata->async.s); hdata->async.result = kmalloc(sizeof(*hdata->async.result), GFP_KERNEL); if (unlikely(!hdata->async.result)) { diff --git a/cryptodev_int.h b/cryptodev_int.h index aacf670..bdf5a46 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -41,6 +41,7 @@ struct cipher_data { int init; /* 0 uninitialized */ int blocksize; int ivsize; + int alignmask; struct { struct crypto_ablkcipher *s; struct cryptodev_result *result; @@ -69,6 +70,7 @@ inline static void cryptodev_cipher_set_iv(struct cipher_data *cdata, struct hash_data { int init; /* 0 uninitialized */ int digestsize; + int alignmask; struct { struct crypto_ahash *s; struct cryptodev_result *result; @@ -101,6 +103,8 @@ struct compat_session_op { compat_uptr_t mackey; /* pointer to mac key data */ uint32_t ses; /* session identifier */ + + uint16_t alignmask; /* alignment constraints */ }; /* input of CIOCCRYPT */ diff --git a/cryptodev_main.c b/cryptodev_main.c index 7326c3d..508c7f9 100644 --- a/cryptodev_main.c +++ b/cryptodev_main.c @@ -110,6 +110,7 @@ struct csession { struct cipher_data cdata; struct hash_data hdata; uint32_t sid; + uint32_t alignmask; #ifdef CRYPTODEV_STATS #if !((COP_ENCRYPT < 2) && (COP_DECRYPT < 2)) #error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something! @@ -272,7 +273,7 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) goto error_hash; } - if (unlikely(copy_from_user(keyp, sop->mackey, + if (sop->mackey && unlikely(copy_from_user(keyp, sop->mackey, sop->mackeylen))) { ret = -EFAULT; goto error_hash; @@ -289,6 +290,10 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) } } + sop->alignmask = ses_new->alignmask = max(ses_new->cdata.alignmask, + ses_new->hdata.alignmask); + dprintk(2, KERN_DEBUG, "%s: got alignmask %d\n", __func__, ses_new->alignmask); + ses_new->array_size = DEFAULT_PREALLOC_PAGES; dprintk(2, KERN_DEBUG, "%s: preallocating for %d user pages\n", __func__, ses_new->array_size); @@ -588,6 +593,11 @@ static int get_userbuf(struct csession *ses, struct kernel_crypt_op *kcop, if (cop->src == NULL) return -EINVAL; + if (!IS_ALIGNED((unsigned long)cop->src, ses->alignmask)) { + dprintk(2, KERN_WARNING, "%s: careful - source address %lx is not %d byte aligned\n", + __func__, (unsigned long)cop->src, ses->alignmask + 1); + } + src_pagecount = PAGECOUNT(cop->src, cop->len); if (!ses->cdata.init) { /* hashing only */ write_src = 0; @@ -597,6 +607,12 @@ static int get_userbuf(struct csession *ses, struct kernel_crypt_op *kcop, dst_pagecount = PAGECOUNT(cop->dst, cop->len); write_src = 0; + + if (!IS_ALIGNED((unsigned long)cop->dst, ses->alignmask)) { + dprintk(2, KERN_WARNING, "%s: careful - destination address %lx is not %d byte aligned\n", + __func__, (unsigned long)cop->dst, ses->alignmask + 1); + } + } (*tot_pages) = pagecount = src_pagecount + dst_pagecount; -- 1.7.3.2 _______________________________________________ Cryptodev-linux-devel mailing list Cryptodev-linux-devel@gna.org https://mail.gna.org/listinfo/cryptodev-linux-devel