trusted-keys: another free memory bugfix
[linux-2.6.git] / security / keys / trusted_defined.c
index aaaa069..7b21795 100644 (file)
@@ -56,7 +56,7 @@ static struct sdesc *init_sdesc(struct crypto_shash *alg)
        return sdesc;
 }
 
-static int TSS_sha1(const unsigned char *data, const unsigned int datalen,
+static int TSS_sha1(const unsigned char *data, unsigned int datalen,
                    unsigned char *digest)
 {
        struct sdesc *sdesc;
@@ -74,7 +74,7 @@ static int TSS_sha1(const unsigned char *data, const unsigned int datalen,
 }
 
 static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
-                      const unsigned int keylen, ...)
+                      unsigned int keylen, ...)
 {
        struct sdesc *sdesc;
        va_list argp;
@@ -101,14 +101,17 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
                if (dlen == 0)
                        break;
                data = va_arg(argp, unsigned char *);
-               if (data == NULL)
-                       return -EINVAL;
+               if (data == NULL) {
+                       ret = -EINVAL;
+                       break;
+               }
                ret = crypto_shash_update(&sdesc->shash, data, dlen);
                if (ret < 0)
-                       goto out;
+                       break;
        }
        va_end(argp);
-       ret = crypto_shash_final(&sdesc->shash, digest);
+       if (!ret)
+               ret = crypto_shash_final(&sdesc->shash, digest);
 out:
        kfree(sdesc);
        return ret;
@@ -117,9 +120,9 @@ out:
 /*
  * calculate authorization info fields to send to TPM
  */
-static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key,
-                            const unsigned int keylen, unsigned char *h1,
-                            unsigned char *h2, unsigned char h3, ...)
+static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
+                       unsigned int keylen, unsigned char *h1,
+                       unsigned char *h2, unsigned char h3, ...)
 {
        unsigned char paramdigest[SHA1_DIGEST_SIZE];
        struct sdesc *sdesc;
@@ -146,15 +149,17 @@ static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key,
                        break;
                data = va_arg(argp, unsigned char *);
                ret = crypto_shash_update(&sdesc->shash, data, dlen);
-               if (ret < 0)
+               if (ret < 0) {
+                       va_end(argp);
                        goto out;
+               }
        }
        va_end(argp);
        ret = crypto_shash_final(&sdesc->shash, paramdigest);
        if (!ret)
-               TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
-                           paramdigest, TPM_NONCE_SIZE, h1,
-                           TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
+               ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
+                                 paramdigest, TPM_NONCE_SIZE, h1,
+                                 TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
 out:
        kfree(sdesc);
        return ret;
@@ -163,11 +168,11 @@ out:
 /*
  * verify the AUTH1_COMMAND (Seal) result from TPM
  */
-static uint32_t TSS_checkhmac1(unsigned char *buffer,
-                              const uint32_t command,
-                              const unsigned char *ononce,
-                              const unsigned char *key,
-                              const unsigned int keylen, ...)
+static int TSS_checkhmac1(unsigned char *buffer,
+                         const uint32_t command,
+                         const unsigned char *ononce,
+                         const unsigned char *key,
+                         unsigned int keylen, ...)
 {
        uint32_t bufsize;
        uint16_t tag;
@@ -219,18 +224,22 @@ static uint32_t TSS_checkhmac1(unsigned char *buffer,
                        break;
                dpos = va_arg(argp, unsigned int);
                ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
-               if (ret < 0)
+               if (ret < 0) {
+                       va_end(argp);
                        goto out;
+               }
        }
        va_end(argp);
        ret = crypto_shash_final(&sdesc->shash, paramdigest);
        if (ret < 0)
                goto out;
+
        ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
                          TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
                          1, continueflag, 0, 0);
        if (ret < 0)
                goto out;
+
        if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
                ret = -EINVAL;
 out:
@@ -241,13 +250,13 @@ out:
 /*
  * verify the AUTH2_COMMAND (unseal) result from TPM
  */
-static uint32_t TSS_checkhmac2(unsigned char *buffer,
-                              const uint32_t command,
-                              const unsigned char *ononce,
-                              const unsigned char *key1,
-                              const unsigned int keylen1,
-                              const unsigned char *key2,
-                              const unsigned int keylen2, ...)
+static int TSS_checkhmac2(unsigned char *buffer,
+                         const uint32_t command,
+                         const unsigned char *ononce,
+                         const unsigned char *key1,
+                         unsigned int keylen1,
+                         const unsigned char *key2,
+                         unsigned int keylen2, ...)
 {
        uint32_t bufsize;
        uint16_t tag;
@@ -309,9 +318,12 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
                        break;
                dpos = va_arg(argp, unsigned int);
                ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
-               if (ret < 0)
+               if (ret < 0) {
+                       va_end(argp);
                        goto out;
+               }
        }
+       va_end(argp);
        ret = crypto_shash_final(&sdesc->shash, paramdigest);
        if (ret < 0)
                goto out;
@@ -319,6 +331,8 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
        ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
                          paramdigest, TPM_NONCE_SIZE, enonce1,
                          TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
+       if (ret < 0)
+               goto out;
        if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
                ret = -EINVAL;
                goto out;
@@ -326,6 +340,8 @@ static uint32_t TSS_checkhmac2(unsigned char *buffer,
        ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
                          paramdigest, TPM_NONCE_SIZE, enonce2,
                          TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
+       if (ret < 0)
+               goto out;
        if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
                ret = -EINVAL;
 out:
@@ -364,8 +380,8 @@ static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len)
        store32(tb, TPM_ORD_GETRANDOM);
        store32(tb, len);
        ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
-       memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
-
+       if (!ret)
+               memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
        return ret;
 }
 
@@ -374,7 +390,7 @@ static int my_get_random(unsigned char *buf, int len)
        struct tpm_buf *tb;
        int ret;
 
-       tb = kzalloc(sizeof *tb, GFP_KERNEL);
+       tb = kmalloc(sizeof *tb, GFP_KERNEL);
        if (!tb)
                return -ENOMEM;
        ret = tpm_get_random(tb, buf, len);
@@ -392,10 +408,13 @@ static int my_get_random(unsigned char *buf, int len)
 static int pcrlock(const int pcrnum)
 {
        unsigned char hash[SHA1_DIGEST_SIZE];
+       int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
-       my_get_random(hash, SHA1_DIGEST_SIZE);
+       ret = my_get_random(hash, SHA1_DIGEST_SIZE);
+       if (ret < 0)
+               return ret;
        return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
 }
 
@@ -403,8 +422,7 @@ static int pcrlock(const int pcrnum)
  * Create an object specific authorisation protocol (OSAP) session
  */
 static int osap(struct tpm_buf *tb, struct osapsess *s,
-               const unsigned char *key, const uint16_t type,
-               const uint32_t handle)
+               const unsigned char *key, uint16_t type, uint32_t handle)
 {
        unsigned char enonce[TPM_NONCE_SIZE];
        unsigned char ononce[TPM_NONCE_SIZE];
@@ -431,9 +449,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
               TPM_NONCE_SIZE);
        memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
                                  TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
-       ret = TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
-                         enonce, TPM_NONCE_SIZE, ononce, 0, 0);
-       return ret;
+       return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
+                          enonce, TPM_NONCE_SIZE, ononce, 0, 0);
 }
 
 /*
@@ -454,7 +471,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
        *handle = LOAD32(tb->data, TPM_DATA_OFFSET);
        memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
               TPM_NONCE_SIZE);
-       return ret;
+       return 0;
 }
 
 struct tpm_digests {
@@ -469,12 +486,12 @@ struct tpm_digests {
  * Have the TPM seal(encrypt) the trusted key, possibly based on
  * Platform Configuration Registers (PCRs). AUTH1 for sealing key.
  */
-static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
-                   const uint32_t keyhandle, const unsigned char *keyauth,
-                   const unsigned char *data, const uint32_t datalen,
+static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
+                   uint32_t keyhandle, const unsigned char *keyauth,
+                   const unsigned char *data, uint32_t datalen,
                    unsigned char *blob, uint32_t *bloblen,
                    const unsigned char *blobauth,
-                   const unsigned char *pcrinfo, const uint32_t pcrinfosize)
+                   const unsigned char *pcrinfo, uint32_t pcrinfosize)
 {
        struct osapsess sess;
        struct tpm_digests *td;
@@ -496,7 +513,7 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
        /* get session for sealing key */
        ret = osap(tb, &sess, keyauth, keytype, keyhandle);
        if (ret < 0)
-               return ret;
+               goto out;
        dump_sess(&sess);
 
        /* calculate encrypted authorization value */
@@ -504,11 +521,11 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
        memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE);
        ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);
        if (ret < 0)
-               return ret;
+               goto out;
 
        ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
        if (ret < 0)
-               return ret;
+               goto out;
        ordinal = htonl(TPM_ORD_SEAL);
        datsize = htonl(datalen);
        pcrsize = htonl(pcrinfosize);
@@ -521,20 +538,23 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
        /* calculate authorization HMAC value */
        if (pcrinfosize == 0) {
                /* no pcr info specified */
-               TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
-                            sess.enonce, td->nonceodd, cont, sizeof(uint32_t),
-                            &ordinal, SHA1_DIGEST_SIZE, td->encauth,
-                            sizeof(uint32_t), &pcrsize, sizeof(uint32_t),
-                            &datsize, datalen, data, 0, 0);
+               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
+                                  sess.enonce, td->nonceodd, cont,
+                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
+                                  td->encauth, sizeof(uint32_t), &pcrsize,
+                                  sizeof(uint32_t), &datsize, datalen, data, 0,
+                                  0);
        } else {
                /* pcr info specified */
-               TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
-                            sess.enonce, td->nonceodd, cont, sizeof(uint32_t),
-                            &ordinal, SHA1_DIGEST_SIZE, td->encauth,
-                            sizeof(uint32_t), &pcrsize, pcrinfosize,
-                            pcrinfo, sizeof(uint32_t), &datsize, datalen,
-                            data, 0, 0);
+               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
+                                  sess.enonce, td->nonceodd, cont,
+                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
+                                  td->encauth, sizeof(uint32_t), &pcrsize,
+                                  pcrinfosize, pcrinfo, sizeof(uint32_t),
+                                  &datsize, datalen, data, 0, 0);
        }
+       if (ret < 0)
+               goto out;
 
        /* build and send the TPM request packet */
        INIT_BUF(tb);
@@ -554,7 +574,7 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
 
        ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
        if (ret < 0)
-               return ret;
+               goto out;
 
        /* calculate the size of the returned Blob */
        sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t));
@@ -569,8 +589,12 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
                             0);
 
        /* copy the returned blob to caller */
-       memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
-       *bloblen = storedsize;
+       if (!ret) {
+               memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
+               *bloblen = storedsize;
+       }
+out:
+       kfree(td);
        return ret;
 }
 
@@ -578,8 +602,8 @@ static int tpm_seal(struct tpm_buf *tb, const uint16_t keytype,
  * use the AUTH2_COMMAND form of unseal, to authorize both key and blob
  */
 static int tpm_unseal(struct tpm_buf *tb,
-                     const uint32_t keyhandle, const unsigned char *keyauth,
-                     const unsigned char *blob, const int bloblen,
+                     uint32_t keyhandle, const unsigned char *keyauth,
+                     const unsigned char *blob, int bloblen,
                      const unsigned char *blobauth,
                      unsigned char *data, unsigned int *datalen)
 {
@@ -614,12 +638,16 @@ static int tpm_unseal(struct tpm_buf *tb,
                pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
                return ret;
        }
-       TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
-                    enonce1, nonceodd, cont, sizeof(uint32_t),
-                    &ordinal, bloblen, blob, 0, 0);
-       TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
-                    enonce2, nonceodd, cont, sizeof(uint32_t),
-                    &ordinal, bloblen, blob, 0, 0);
+       ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
+                          enonce1, nonceodd, cont, sizeof(uint32_t),
+                          &ordinal, bloblen, blob, 0, 0);
+       if (ret < 0)
+               return ret;
+       ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
+                          enonce2, nonceodd, cont, sizeof(uint32_t),
+                          &ordinal, bloblen, blob, 0, 0);
+       if (ret < 0)
+               return ret;
 
        /* build and send TPM request packet */
        INIT_BUF(tb);
@@ -650,10 +678,12 @@ static int tpm_unseal(struct tpm_buf *tb,
                             sizeof(uint32_t), TPM_DATA_OFFSET,
                             *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
                             0);
-       if (ret < 0)
+       if (ret < 0) {
                pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
+               return ret;
+       }
        memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
-       return ret;
+       return 0;
 }
 
 /*
@@ -697,11 +727,11 @@ static int key_unseal(struct trusted_key_payload *p,
 
        ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
                         o->blobauth, p->key, &p->key_len);
-       /* pull migratable flag out of sealed key */
-       p->migratable = p->key[--p->key_len];
-
        if (ret < 0)
                pr_info("trusted_key: srkunseal failed (%d)\n", ret);
+       else
+               /* pull migratable flag out of sealed key */
+               p->migratable = p->key[--p->key_len];
 
        kfree(tb);
        return ret;
@@ -854,12 +884,11 @@ static struct trusted_key_options *trusted_options_alloc(void)
        struct trusted_key_options *options;
 
        options = kzalloc(sizeof *options, GFP_KERNEL);
-       if (!options)
-               return options;
-
-       /* set any non-zero defaults */
-       options->keytype = SRK_keytype;
-       options->keyhandle = SRKHANDLE;
+       if (options) {
+               /* set any non-zero defaults */
+               options->keytype = SRK_keytype;
+               options->keyhandle = SRKHANDLE;
+       }
        return options;
 }
 
@@ -872,9 +901,8 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
        if (ret < 0)
                return p;
        p = kzalloc(sizeof *p, GFP_KERNEL);
-
-       /* migratable by default */
-       p->migratable = 1;
+       if (p)
+               p->migratable = 1; /* migratable by default */
        return p;
 }
 
@@ -888,7 +916,7 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
  * On success, return 0. Otherwise return errno.
  */
 static int trusted_instantiate(struct key *key, const void *data,
-                              const size_t datalen)
+                              size_t datalen)
 {
        struct trusted_key_payload *payload = NULL;
        struct trusted_key_options *options = NULL;
@@ -971,8 +999,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
 /*
  * trusted_update - reseal an existing key with new PCR values
  */
-static int trusted_update(struct key *key, const void *data,
-                         const size_t datalen)
+static int trusted_update(struct key *key, const void *data, size_t datalen)
 {
        struct trusted_key_payload *p = key->payload.data;
        struct trusted_key_payload *new_p;