diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-08-28 17:22:27 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-08-28 17:22:27 +0200 |
commit | a8cdc5f8db88621fae634d09100ab65be94616f8 (patch) | |
tree | 928117f741b78391ee0c3d79c763a3544a0ddb78 | |
parent | ab6e352c9674b7bfbab5d9de77962a31958006b4 (diff) |
add refcount-use-after-free.patch
-rw-r--r-- | debian/patches/refcount-use-after-free.patch | 180 | ||||
-rw-r--r-- | debian/patches/series | 1 |
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 |