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

Reply via email to