bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] include: detect use-after-free errors using the reference co


From: Samuel Thibault
Subject: Re: [PATCH] include: detect use-after-free errors using the reference counts
Date: Sun, 31 Aug 2014 20:04:53 +0200
User-agent: Mutt/1.5.21+34 (58baf7c9f32f) (2010-12-30)

Ack.

Justus Winter, le Sun 31 Aug 2014 19:59:48 +0200, a écrit :
> * include/refcount.h (refcount_init): There must be at least one
> reference at initialization time.
> (refcounts_init): Likewise.
> (refcount_unsafe_ref): New function retaining the previous
> functionality of refcount_ref.  It is occasionally useful to raise the
> reference count again after it dropped to zero.
> (refcounts_unsafe_ref): Likewise.
> (refcounts_unsafe_weak_ref): Likewise.
> (refcount_ref): Detect use-after-free errors.
> (refcounts_ref): Likewise.
> (refcounts_ref_weak): Likewise.
> * libtrivfs/protid-clean.c (trivfs_clean_protid): Use refcount_unsafe_ref.
> ---
>  include/refcount.h       | 73 
> ++++++++++++++++++++++++++++++++++++++++++------
>  libtrivfs/protid-clean.c |  2 +-
>  2 files changed, 66 insertions(+), 9 deletions(-)
> 
> diff --git a/include/refcount.h b/include/refcount.h
> index 785b052..ebde42d 100644
> --- a/include/refcount.h
> +++ b/include/refcount.h
> @@ -31,18 +31,23 @@
>  /* 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;
>  }
>  
>  /* Increment REF.  Return the result of the operation.  This function
>     uses atomic operations.  It is not required to serialize calls to
> -   this function.  */
> +   this function.
> +
> +   This is the unsafe version of refcount_ref.  refcount_ref also
> +   checks for use-after-free errors.  When in doubt, use that one
> +   instead.  */
>  static inline unsigned int
> -refcount_ref (refcount_t *ref)
> +refcount_unsafe_ref (refcount_t *ref)
>  {
>    unsigned int r;
>    r = __atomic_add_fetch (ref, 1, __ATOMIC_RELAXED);
> @@ -50,6 +55,18 @@ refcount_ref (refcount_t *ref)
>    return r;
>  }
>  
> +/* Increment REF.  Return the result of the operation.  This function
> +   uses atomic operations.  It is not required to serialize calls to
> +   this function.  */
> +static inline unsigned int
> +refcount_ref (refcount_t *ref)
> +{
> +  unsigned int r;
> +  r = refcount_unsafe_ref (ref);
> +  assert (r != 1 || !"refcount detected use-after-free!");
> +  return r;
> +}
> +
>  /* Decrement REF.  Return the result of the operation.  This function
>     uses atomic operations.  It is not required to serialize calls to
>     this function.  */
> @@ -101,19 +118,25 @@ 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 };
>  }
>  
>  /* Increment the hard reference count of REF.  If RESULT is not NULL,
>     the result of the operation is written there.  This function uses
>     atomic operations.  It is not required to serialize calls to this
> -   function.  */
> +   function.
> +
> +   This is the unsafe version of refcounts_ref.  refcounts_ref also
> +   checks for use-after-free errors.  When in doubt, use that one
> +   instead.  */
>  static inline void
> -refcounts_ref (refcounts_t *ref, struct references *result)
> +refcounts_unsafe_ref (refcounts_t *ref, struct references *result)
>  {
>    const union _references op = { .references = { .hard = 1 } };
>    union _references r;
> @@ -123,6 +146,21 @@ refcounts_ref (refcounts_t *ref, struct references 
> *result)
>      *result = r.references;
>  }
>  
> +/* Increment the hard reference count of REF.  If RESULT is not NULL,
> +   the result of the operation is written there.  This function uses
> +   atomic operations.  It is not required to serialize calls to this
> +   function.  */
> +static inline void
> +refcounts_ref (refcounts_t *ref, struct references *result)
> +{
> +  struct references r;
> +  refcounts_unsafe_ref (ref, &r);
> +  assert (! (r.hard == 1 && r.weak == 0)
> +          || !"refcount detected use-after-free!");
> +  if (result)
> +    *result = r;
> +}
> +
>  /* Decrement the hard reference count of REF.  If RESULT is not NULL,
>     the result of the operation is written there.  This function uses
>     atomic operations.  It is not required to serialize calls to this
> @@ -200,9 +238,13 @@ refcounts_demote (refcounts_t *ref, struct references 
> *result)
>  /* Increment the weak reference count of REF.  If RESULT is not NULL,
>     the result of the operation is written there.  This function uses
>     atomic operations.  It is not required to serialize calls to this
> -   function.  */
> +   function.
> +
> +   This is the unsafe version of refcounts_ref_weak.
> +   refcounts_ref_weak also checks for use-after-free errors.  When in
> +   doubt, use that one instead.  */
>  static inline void
> -refcounts_ref_weak (refcounts_t *ref, struct references *result)
> +refcounts_unsafe_ref_weak (refcounts_t *ref, struct references *result)
>  {
>    const union _references op = { .references = { .weak = 1 } };
>    union _references r;
> @@ -212,6 +254,21 @@ refcounts_ref_weak (refcounts_t *ref, struct references 
> *result)
>      *result = r.references;
>  }
>  
> +/* Increment the weak reference count of REF.  If RESULT is not NULL,
> +   the result of the operation is written there.  This function uses
> +   atomic operations.  It is not required to serialize calls to this
> +   function.  */
> +static inline void
> +refcounts_ref_weak (refcounts_t *ref, struct references *result)
> +{
> +  struct references r;
> +  refcounts_unsafe_ref_weak (ref, &r);
> +  assert (! (r.hard == 0 && r.weak == 1)
> +          || !"refcount detected use-after-free!");
> +  if (result)
> +    *result = r;
> +}
> +
>  /* Decrement the weak reference count of REF.  If RESULT is not NULL,
>     the result of the operation is written there.  This function uses
>     atomic operations.  It is not required to serialize calls to this
> diff --git a/libtrivfs/protid-clean.c b/libtrivfs/protid-clean.c
> index adc5e98..ff6cc16 100644
> --- a/libtrivfs/protid-clean.c
> +++ b/libtrivfs/protid-clean.c
> @@ -36,7 +36,7 @@ trivfs_clean_protid (void *arg)
>        if (refcount_deref (&cred->po->refcnt) == 0)
>          {
>            /* Reacquire a reference while we call the hook.  */
> -          refcount_ref (&cred->po->refcnt);
> +          refcount_unsafe_ref (&cred->po->refcnt);
>            (*trivfs_peropen_destroy_hook) (cred->po);
>            if (refcount_deref (&cred->po->refcnt) == 0)
>              {
> -- 
> 2.1.0
> 

-- 
Samuel
 La carte réseau fournie par cybercable (sn2000) ne va-t-elle que sur
 bus isa ou peut-on aussi la mettre sur bus PCI.
 Merci de m'éclairer.
 -+- JP in le Neuneu Pète un Câble : Une carte dans chaque port -+-



reply via email to

[Prev in Thread] Current Thread [Next in Thread]