summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
Diffstat (limited to 'debian')
-rw-r--r--debian/patches/refcount-use-after-free.patch180
-rw-r--r--debian/patches/series1
2 files changed, 181 insertions, 0 deletions
diff --git a/debian/patches/refcount-use-after-free.patch b/debian/patches/refcount-use-after-free.patch
new file mode 100644
index 00000000..3359f7a4
--- /dev/null
+++ b/debian/patches/refcount-use-after-free.patch
@@ -0,0 +1,180 @@
+diff --git a/include/refcount.h b/include/refcount.h
+index 785b052..533fdfe 100644
+--- a/include/refcount.h
++++ b/include/refcount.h
+@@ -31,10 +31,11 @@
+ /* An opaque type. You must not access these values directly. */
+ typedef unsigned int refcount_t;
+
+-/* Initialize REF with REFERENCES. */
++/* Initialize REF with REFERENCES. REFERENCES must not be zero. */
+ static inline void
+ refcount_init (refcount_t *ref, unsigned int references)
+ {
++ assert (references > 0 || !"references must not be zero!");
+ *ref = references;
+ }
+
+@@ -47,6 +48,7 @@ refcount_ref (refcount_t *ref)
+ unsigned int r;
+ r = __atomic_add_fetch (ref, 1, __ATOMIC_RELAXED);
+ assert (r != UINT_MAX || !"refcount overflowed!");
++ assert (r != 1 || !"refcount detected use after free!");
+ return r;
+ }
+
+@@ -101,10 +103,12 @@ union _references {
+ uint64_t value;
+ };
+
+-/* Initialize REF with HARD and WEAK references. */
++/* Initialize REF with HARD and WEAK references. HARD and WEAK must
++ not both be zero. */
+ static inline void
+ refcounts_init (refcounts_t *ref, uint32_t hard, uint32_t weak)
+ {
++ assert ((hard != 0 || weak != 0) || !"references must not both be zero!");
+ ref->references = (struct references) { .hard = hard, .weak = weak };
+ }
+
+@@ -119,6 +123,8 @@ refcounts_ref (refcounts_t *ref, struct references *result)
+ union _references r;
+ r.value = __atomic_add_fetch (&ref->value, op.value, __ATOMIC_RELAXED);
+ assert (r.references.hard != UINT32_MAX || !"refcount overflowed!");
++ assert (! (r.references.hard == 1 && r.references.weak == 0)
++ || !"refcount detected use after free!");
+ if (result)
+ *result = r.references;
+ }
+@@ -208,6 +214,8 @@ refcounts_ref_weak (refcounts_t *ref, struct references *result)
+ union _references r;
+ r.value = __atomic_add_fetch (&ref->value, op.value, __ATOMIC_RELAXED);
+ assert (r.references.weak != UINT32_MAX || !"refcount overflowed!");
++ assert (! (r.references.hard == 0 && r.references.weak == 1)
++ || !"refcount detected use after free!");
+ if (result)
+ *result = r.references;
+ }
+diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h
+index e328527..e59ba99 100644
+--- a/libdiskfs/diskfs.h
++++ b/libdiskfs/diskfs.h
+@@ -820,12 +820,12 @@ diskfs_create_node (struct node *dir, const char *name, mode_t mode,
+ struct dirstat *ds);
+
+ /* Create and return a protid for an existing peropen PO in CRED,
+- referring to user USER. */
++ referring to user USER. On success, consume a reference to PO. */
+ error_t diskfs_create_protid (struct peropen *po, struct iouser *user,
+ struct protid **cred);
+
+ /* Build and return in CRED a protid which has no user identification, for
+- peropen PO. */
++ peropen PO. On success, consume a reference to PO. */
+ error_t diskfs_start_protid (struct peropen *po, struct protid **cred);
+
+ /* Finish building protid CRED started with diskfs_start_protid;
+diff --git a/libdiskfs/io-duplicate.c b/libdiskfs/io-duplicate.c
+index 45c4df5..a2e568b 100644
+--- a/libdiskfs/io-duplicate.c
++++ b/libdiskfs/io-duplicate.c
+@@ -32,6 +32,7 @@ diskfs_S_io_duplicate (struct protid *cred,
+
+ pthread_mutex_lock (&cred->po->np->lock);
+
++ refcount_ref (&cred->po->refcnt);
+ err = diskfs_create_protid (cred->po, cred->user, &newpi);
+ if (! err)
+ {
+@@ -39,6 +40,8 @@ diskfs_S_io_duplicate (struct protid *cred,
+ *portpoly = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newpi);
+ }
++ else
++ refcount_deref (&cred->po->refcnt);
+
+ pthread_mutex_unlock (&cred->po->np->lock);
+
+diff --git a/libdiskfs/io-reauthenticate.c b/libdiskfs/io-reauthenticate.c
+index 69d78bc..649315f 100644
+--- a/libdiskfs/io-reauthenticate.c
++++ b/libdiskfs/io-reauthenticate.c
+@@ -35,11 +35,13 @@ diskfs_S_io_reauthenticate (struct protid *cred,
+ are a simpleroutine, so callers won't know to restart. */
+
+ pthread_mutex_lock (&cred->po->np->lock);
++ refcount_ref (&cred->po->refcnt);
+ do
+ err = diskfs_start_protid (cred->po, &newcred);
+ while (err == EINTR);
+ if (err)
+ {
++ refcount_deref (&cred->po->refcnt);
+ pthread_mutex_unlock (&cred->po->np->lock);
+ return err;
+ }
+diff --git a/libdiskfs/io-restrict-auth.c b/libdiskfs/io-restrict-auth.c
+index 011aa19..80c0b20 100644
+--- a/libdiskfs/io-restrict-auth.c
++++ b/libdiskfs/io-restrict-auth.c
+@@ -41,6 +41,7 @@ diskfs_S_io_restrict_auth (struct protid *cred,
+ return err;
+
+ pthread_mutex_lock (&cred->po->np->lock);
++ refcount_ref (&cred->po->refcnt);
+ err = diskfs_create_protid (cred->po, user, &newpi);
+ if (! err)
+ {
+@@ -48,6 +49,8 @@ diskfs_S_io_restrict_auth (struct protid *cred,
+ *newportpoly = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newpi);
+ }
++ else
++ refcount_deref (&cred->po->refcnt);
+ pthread_mutex_unlock (&cred->po->np->lock);
+
+ iohelp_free_iouser (user);
+diff --git a/libdiskfs/peropen-make.c b/libdiskfs/peropen-make.c
+index 6d5ca01..788b9a7 100644
+--- a/libdiskfs/peropen-make.c
++++ b/libdiskfs/peropen-make.c
+@@ -31,7 +31,7 @@ diskfs_make_peropen (struct node *np, int flags, struct peropen *context,
+
+ po->filepointer = 0;
+ po->lock_status = LOCK_UN;
+- refcount_init (&po->refcnt, 0);
++ refcount_init (&po->refcnt, 1);
+ po->openstat = flags;
+ po->np = np;
+ po->path = NULL;
+diff --git a/libdiskfs/protid-make.c b/libdiskfs/protid-make.c
+index 22aaa2e..0b09299 100644
+--- a/libdiskfs/protid-make.c
++++ b/libdiskfs/protid-make.c
+@@ -20,7 +20,7 @@
+ #include <assert.h>
+
+ /* Build and return in CRED a protid which has no user identification, for
+- peropen PO. */
++ peropen PO. On success, consume a reference to PO. */
+ error_t
+ diskfs_start_protid (struct peropen *po, struct protid **cred)
+ {
+@@ -29,7 +29,7 @@ diskfs_start_protid (struct peropen *po, struct protid **cred)
+ sizeof (struct protid), cred);
+ if (! err)
+ {
+- refcount_ref (&po->refcnt);
++ /* Consume a reference to po. */
+ (*cred)->po = po;
+ (*cred)->shared_object = MACH_PORT_NULL;
+ (*cred)->mapped = 0;
+@@ -56,7 +56,7 @@ diskfs_finish_protid (struct protid *cred, struct iouser *user)
+ }
+
+ /* Create and return a protid for an existing peropen PO in CRED for
+- USER. */
++ USER. On success, consume a reference to PO. */
+ error_t
+ diskfs_create_protid (struct peropen *po, struct iouser *user,
+ struct protid **cred)
diff --git a/debian/patches/series b/debian/patches/series
index f76bcfea..19c77855 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -54,3 +54,4 @@ fix-net_rcv_msg.patch
#pp-dde.patch
#pp-random.patch
+refcount-use-after-free.patch