DragonFlyBSD Kernel Audit
DF-2764 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/vfs_jops.c
+++ b/sys/kern/vfs_jops.c
@@ -1021,6 +1021,24 @@
     struct mount *mp;
     void *save;
     int error;
+    struct uio uio_copy;
+    struct iovec uio_one_iovec;
+
+    /*
+     * The underlying VOP consumes the uio (uiomove advances the iovecs
+     * in place), so the attribute value must be snapshotted BEFORE the
+     * operation, exactly like journal_write() does.
+     */
+    uio_copy = *ap->a_uio;
+    if (uio_copy.uio_iovcnt == 1) {
+	uio_one_iovec = ap->a_uio->uio_iov[0];
+	uio_copy.uio_iov = &uio_one_iovec;
+    } else {
+	uio_copy.uio_iov = kmalloc(uio_copy.uio_iovcnt * sizeof(struct iovec),
+				    M_JOURNAL, M_WAITOK);
+	bcopy(ap->a_uio->uio_iov, uio_copy.uio_iov,
+		uio_copy.uio_iovcnt * sizeof(struct iovec));
+    }
 
     mp = ap->a_head.a_ops->head.vv_mount;
     jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETEXTATTR);
@@ -1036,11 +1054,14 @@
 	    jrecord_leaf(jrec, JLEAF_ATTRNAME, ap->a_attrname,
 			strlen(ap->a_attrname));
 	    save = jrecord_push(jrec, JTYPE_REDO);
-	    jrecord_write_uio(jrec, JLEAF_FILEDATA, ap->a_uio);
+	    jrecord_write_uio(jrec, JLEAF_FILEDATA, &uio_copy);
 	    jrecord_pop(jrec, save);
 	}
     }
     jreclist_done(mp, &jreclist, error);
+
+    if (uio_copy.uio_iov != &uio_one_iovec)
+	kfree(uio_copy.uio_iov, M_JOURNAL);
     return (error);
 }