Small morning patch for bd_fd filter which closes "major security vulnerability"
 described at http://off.net/~jme/loopdev_vul.html

Author's quite: "about 3 years ago i published a paper describing how an 
attacker would be able
to modify the content of the encrypted device without being detected."

Small archive of the descussion at: 
http://mail.nl.linux.org/linux-crypto/2005-01/msg00040.html

It is provideed to show how easy is bd filters creation.

Thank you for your attention :)

P.S. userspace ubd.c patch is not attached, it is 32 lines copy/allocation.

--- orig/bd_fd.c
+++ mod/bd_fd.c
@@ -29,6 +29,7 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/file.h>
+#include <linux/crypto.h>
 
 #include "bd.h"
 #include "bd_filter.h"
@@ -37,6 +38,7 @@
 static int bd_fd_transfer(struct bd_transfer *);
 static int bd_fd_init(struct bd_device *, struct bd_filter *);
 static void bd_fd_fini(struct bd_device *, struct bd_filter *);
+static int bd_fd_check_media(struct bd_device *dev, struct bd_filter *f, int 
size);
 
 static struct bd_main_filter fd_filter = 
 {
@@ -126,9 +128,11 @@
 {
        struct bd_fd_private *p;
                struct bd_fd_user *u = f->priv;
-       int err;
+       int err, size;
+
+       size = f->priv_size - sizeof(*u);
 
-       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       p = kmalloc(sizeof(*p) + size, GFP_KERNEL);
        if (!p) {
                dprintk("Failed to allocate new bd_fd priavte structure in 
dev=%s, filter=%s.\n", 
                                dev->name, f->mf->name);
@@ -136,8 +140,11 @@
        }
 
        memset(p, 0, sizeof(*p));
-
        memcpy(&p->u, u, sizeof(p->u));
+       if (size) {
+               p->hmac = (u8 *)(p+1);
+               memcpy(p->hmac, u+1, size);
+       }
 
        dprintk("%s: filter=%s, flags=%08x.\n", __func__, f->mf->name, 
f->mf->flags);
        
@@ -152,8 +159,11 @@
        err = bd_set_fd(dev, p);
        if (err)
                return err;
+
+       if (size)
+               err = bd_fd_check_media(dev, f, size);
        
-       return 0;
+       return err;
 }
 
 static void bd_fd_fini(struct bd_device *dev, struct bd_filter *f)
@@ -305,6 +315,93 @@
        return err;
 }
 
+static void bd_fd_complete(struct bd_transfer *t)
+{
+}
+#define SHA512_DIGEST_SIZE 64
+static int bd_fd_check_media(struct bd_device *dev, struct bd_filter *f, int 
size)
+{
+       struct crypto_tfm *tfm;
+       int err, i; 
+       loff_t storage_size, pos;
+       struct bd_fd_private *p = f->priv;
+       struct page *pg;
+       struct bd_transfer t;
+       u8 hmac[SHA512_DIGEST_SIZE];
+       u8 scratch[SHA512_DIGEST_SIZE];
+       struct scatterlist sg;
+
+       if (size != SHA512_DIGEST_SIZE)
+               return -EINVAL;
+       
+       tfm = crypto_alloc_tfm("sha512", 0);
+       if (!tfm) {
+               dprintk("Failed to create sha512 tfm for device %s.\n", 
dev->name);
+               return -ENODEV;
+       }
+
+       storage_size = bd_get_size(dev, p);
+       if (!storage_size) {
+               dprintk("Storage size of %s is %llu.\n", dev->name, 
storage_size);
+               err = -EINVAL;
+               goto err_out_free_tfm;
+       }
+
+       pg = alloc_pages(GFP_KERNEL, 0);
+       if (!pg) {
+               dprintk("Failed to get free scratch page for device %s.\n", 
dev->name);
+               err = -ENOMEM;
+               goto err_out_free_tfm;
+       }
+
+       memset(&t, 0, sizeof(t));
+
+       for (pos=0; pos<storage_size;) {
+               t.src.page = pg;
+               t.src.off = 0;
+               t.src.size = (storage_size - pos > 
PAGE_SIZE)?PAGE_SIZE:(storage_size - pos);
+               t.cmd = READ;
+               t.pos = pos;
+               t.f = f;
+               t.f->complete = bd_fd_complete;
+               
+               file_bd_read(&t);
+
+               pos += PAGE_SIZE;
+
+               sg.page = pg;
+               sg.offset = 0;
+               sg.length = PAGE_SIZE;
+
+               crypto_digest_digest(tfm, &sg, 1, scratch);
+
+               for (i=0; i<sizeof(hmac); ++i) {
+                       hmac[i] ^= scratch[i];
+               }
+       }
+
+       __free_pages(pg, 0);
+
+err_out_free_tfm:
+       crypto_free_tfm(tfm);
+
+       err = memcmp(hmac, p->hmac, sizeof(hmac));
+
+       printk("Calculated: ");
+       for (i=0; i<sizeof(hmac); ++i) {
+               printk("%02x ", hmac[i]);
+       }
+       printk("\n");
+       printk("Provided  : ");
+       for (i=0; i<sizeof(hmac); ++i) {
+               printk("%02x ", p->hmac[i]);
+       }
+       printk("\n");
+               
+       return err;
+}
+
+
 int __devinit bd_fd_init_dev(void)
 {
        int err;


--- orig/bd_fd.h
+++ mod/bd_fd.h
@@ -34,6 +34,8 @@
        struct bd_fd_user       u;
 
        struct file             *file;
+
+       u8                      *hmac;
 };
 
 #endif /* __KERNEL__ */



        Evgeniy Polyakov

Only failure makes us experts. -- Theo de Raadt
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to