]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Do not attempt access beyond the declared end of the dn_blkptr array
authorJan Engelhardt <jengelh@inai.de>
Fri, 18 Jul 2014 18:00:27 +0000 (20:00 +0200)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 22 Jul 2014 16:55:37 +0000 (09:55 -0700)
This loop in dmu_objset_write_ready():

for (i = 0; i < dnp->dn_nblkptr; i++)
bp->blk_fill += dnp->dn_blkptr[i].blk_fill;

invokes _undefined behavior_ for the (common) case of dn_nblkptr=3,
therefore, the compiler is free to do whatever it wants (such as
optimizing it away, or otherwise messing up your expections).

The fix is to be honest about the array size.

Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2511
Closes #2010

include/sys/dnode.h

index 55b87bc394ff5b546f811cf36eb750208f1332ab..fa0aa4bb7a98a0432fcc7de2e2c3da2563b98e80 100644 (file)
@@ -138,9 +138,31 @@ typedef struct dnode_phys {
 
        uint64_t dn_pad3[4];
 
-       blkptr_t dn_blkptr[1];
-       uint8_t dn_bonus[DN_MAX_BONUSLEN - sizeof (blkptr_t)];
-       blkptr_t dn_spill;
+       /*
+        * The tail region is 448 bytes, and there are three ways to
+        * look at it.
+        *
+        * 0       64      128     192     256     320     384     448 (offset)
+        * +---------------+---------------+---------------+-------+
+        * | dn_blkptr[0]  | dn_blkptr[1]  | dn_blkptr[2]  | /     |
+        * +---------------+---------------+---------------+-------+
+        * | dn_blkptr[0]  | dn_bonus[0..319]                      |
+        * +---------------+-----------------------+---------------+
+        * | dn_blkptr[0]  | /                     | dn_spill      |
+        * +---------------+-----------------------+---------------+
+        */
+       union {
+               blkptr_t dn_blkptr[1+DN_MAX_BONUSLEN/sizeof (blkptr_t)];
+               struct {
+                       blkptr_t __dn_ignore1;
+                       uint8_t dn_bonus[DN_MAX_BONUSLEN];
+               };
+               struct {
+                       blkptr_t __dn_ignore2;
+                       uint8_t __dn_ignore3[DN_MAX_BONUSLEN-sizeof (blkptr_t)];
+                       blkptr_t dn_spill;
+               };
+       };
 } dnode_phys_t;
 
 typedef struct dnode {