[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 -+-