padlock - Properly align data
authorAlex Hornung <ahornung@gmail.com>
Sat, 21 Aug 2010 10:46:17 +0000 (11:46 +0100)
committerAlex Hornung <ahornung@gmail.com>
Sat, 21 Aug 2010 13:12:28 +0000 (14:12 +0100)
* Most parameters to the xcrypt instruction need to be aligned to 16
  bytes. So far we haven't been aligning some of the data such as the
  key, iv and control structure. Refer to the "VIA PadLock Programming
  Guide" for more details.

* Address this by allocating a bit more
  space and setting stuff up at 16-byte boundaries and ensuring gcc
  aligns the whole structure 16-bytish. While this wastes some memory,
  it is negligible.

* This fixes the issue with encryption and decryption with padlock
  causing general protection faults.

Reported-by: Jan Lentfer (lentferj@)
sys/crypto/via/padlock.c
sys/crypto/via/padlock.h

index de8b0eb..7054153 100644 (file)
@@ -155,7 +155,7 @@ padlock_detach(device_t dev)
        }
        while ((ses = TAILQ_FIRST(&sc->sc_sessions)) != NULL) {
                TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
-               kfree(ses, M_PADLOCK);
+               kfree(ses->ses_freeaddr, M_PADLOCK);
        }
        lockuninit(&sc->sc_sessions_lock);
        crypto_unregister_all(sc->sc_cid);
@@ -166,7 +166,7 @@ static int
 padlock_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri)
 {
        struct padlock_softc *sc = device_get_softc(dev);
-       struct padlock_session *ses = NULL;
+       struct padlock_session *ases, *ses = NULL;
        struct cryptoini *encini, *macini;
        int error;
 
@@ -215,11 +215,19 @@ padlock_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri)
         */
        ses = TAILQ_FIRST(&sc->sc_sessions);
        if (ses == NULL || ses->ses_used) {
-               ses = kmalloc(sizeof(*ses), M_PADLOCK, M_NOWAIT | M_ZERO);
+               ses = kmalloc(sizeof(*ses) + 16, M_PADLOCK, M_NOWAIT | M_ZERO);
                if (ses == NULL) {
                        lockmgr(&sc->sc_sessions_lock, LK_RELEASE);
                        return (ENOMEM);
                }
+               /* Check if 'ses' is 16-byte aligned. If not, align it. */
+               if (((uintptr_t)ses & 0xf) != 0) {
+                       ases = PADLOCK_ALIGN(ses);
+                       ases->ses_freeaddr = ses;
+                       ses = ases;
+               } else {
+                       ses->ses_freeaddr = ses;
+               }
                ses->ses_id = sc->sc_sid++;
        } else {
                TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
index 96707ba..ca82e6a 100644 (file)
@@ -70,7 +70,8 @@ struct padlock_session {
        int             ses_used;
        uint32_t        ses_id;
        TAILQ_ENTRY(padlock_session) ses_next;
-};
+       void            *ses_freeaddr;
+} __aligned(16);
 
 #define        PADLOCK_ALIGN(p)        (void *)(roundup2((uintptr_t)(p), 16))