All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Zijlstra <peterz@infradead.org>
To: David Windsor <dwindsor@gmail.com>
Cc: mingo@kernel.org, elena.reshetova@intel.com,
	linux-kernel@vger.kernel.org,
	kernel-hardening@lists.openwall.com
Subject: [kernel-hardening] Re: [PATCH] refcount: add refcount_t API kernel-doc comments
Date: Wed, 1 Mar 2017 09:47:50 +0100	[thread overview]
Message-ID: <20170301084750.GY6515@twins.programming.kicks-ass.net> (raw)
In-Reply-To: <1488339285-23777-1-git-send-email-dwindsor@gmail.com>

On Tue, Feb 28, 2017 at 10:34:45PM -0500, David Windsor wrote:

> diff --git a/lib/refcount.c b/lib/refcount.c
> index 1d33366..30e0927 100644
> --- a/lib/refcount.c
> +++ b/lib/refcount.c
> @@ -37,6 +37,15 @@
>  #include <linux/refcount.h>
>  #include <linux/bug.h>
>  
> +/**
> + * refcount_add_not_zero - add a value to a refcount unless the refcount is 0
> + * @i: the value to add to the refcount
> + * @r: the refcount
> + *
> + * Will saturate at UINT_MAX and WARN.
> + *
> + * Return: false if the refcount is 0, true otherwise.
> + */
>  bool refcount_add_not_zero(unsigned int i, refcount_t *r)
>  {
>  	unsigned int old, new, val = atomic_read(&r->refs);
> @@ -64,18 +73,30 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_add_not_zero);
>  
> +/**
> + * refcount_add - add a value to a refcount
> + * @i: the value to add to the refcount
> + * @r: the refcount
> + *
> + * Similar to atomic_add(), will saturate at UINT_MAX and WARN.
> + */
>  void refcount_add(unsigned int i, refcount_t *r)
>  {
>  	WARN(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n");
>  }
>  EXPORT_SYMBOL_GPL(refcount_add);

Usage of both of these should be discouraged, add/sub on refcounts is
'odd'. Also, both these lack the comment on memory ordering, copy/paste
from inc_not_zero/inc.

> -/*
> +/**
> + * refcount_inc_not_zero - increment a refcount unless it is 0
> + * @r: the refcount to increment
> + *
>   * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN.
>   *
>   * Provides no memory ordering, it is assumed the caller has guaranteed the
>   * object memory to be stable (RCU, etc.). It does provide a control dependency
>   * and thereby orders future stores. See the comment on top.
> + *
> + * Return: false if the refcount is 0, true otherwise

An alternative interpretation is: return true if the increment happened,
false otherwise. But given the saturation semantics that might be
awkward, but its the one I find easier to work with.

>   */
>  bool refcount_inc_not_zero(refcount_t *r)
>  {
> @@ -103,11 +124,16 @@ bool refcount_inc_not_zero(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_inc_not_zero);
>  
> -/*
> +/**
> + * refcount_inc - increment a refcount
> + * @r: the refcount to increment
> + *
>   * Similar to atomic_inc(), will saturate at UINT_MAX and WARN.
>   *
>   * Provides no memory ordering, it is assumed the caller already has a
>   * reference on the object, will WARN when this is not so.
> + *
> + * Will WARN if refcount is 0.

I think that duplicates the final part of the prior sentence in intent.

Also, it might be useful to explain why.

>   */
>  void refcount_inc(refcount_t *r)
>  {
> @@ -115,6 +141,22 @@ void refcount_inc(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_inc);
>  
> +/**
> + * refcount_sub_and_test - subtract from a refcount and test if it is 0
> + * @i: amount to subtract from the refcount
> + * @r: the refcount
> + *
> + * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
> + * decrement when saturated at UINT_MAX.

It will equally fail the subtraction on underflow and return false
(didn't hit 0) and leak.

> + *
> + * Provides release memory ordering, such that prior loads and stores are done
> + * before, and provides a control dependency such that free() must come after.
> + * See the comment on top.
> + *
> + * Return: true if the resulting refcount is greater than 0, false if the
> + * resulting refcount is 0, the refcount is saturated at UINT_MAX or the
> + * subtraction operation causes an underflow.

I think you got that wrong, will return true when we hit 0, false
otherwise.

Remember; one writes:

	if (dec_and_test(&obj->ref))
		free(obj);

> + */
>  bool refcount_sub_and_test(unsigned int i, refcount_t *r)
>  {
>  	unsigned int old, new, val = atomic_read(&r->refs);
> @@ -140,13 +182,20 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_sub_and_test);

As with add, sub should be discouraged.

> -/*
> +/**
> + * refcount_dec_and_test - decrement a refcount and test if it is 0
> + * @r: the refcount
> + *
>   * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
>   * decrement when saturated at UINT_MAX.
>   *
>   * Provides release memory ordering, such that prior loads and stores are done
>   * before, and provides a control dependency such that free() must come after.
>   * See the comment on top.
> + *
> + * Return: true if the resulting refcount is greater than 0, false if the
> + * resulting refcount is 0, the refcount is saturated at UINT_MAX or the
> + * decrement operation causes an underflow.

got that similarly wrong.

>   */
>  bool refcount_dec_and_test(refcount_t *r)
>  {
> @@ -154,21 +203,26 @@ bool refcount_dec_and_test(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_dec_and_test);
>  
> -/*
> +/**
> + * refcount_dec - decrement a refcount
> + * @r: the refcount
> + *
>   * Similar to atomic_dec(), it will WARN on underflow and fail to decrement
>   * when saturated at UINT_MAX.
>   *
>   * Provides release memory ordering, such that prior loads and stores are done
>   * before.
>   */
> -
>  void refcount_dec(refcount_t *r)
>  {
>  	WARN(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n");
>  }
>  EXPORT_SYMBOL_GPL(refcount_dec);
>  
> -/*
> +/**
> + * refcount_dec_if_one - decrement a refcount if it is 1
> + * @r: the refcount
> + *
>   * No atomic_t counterpart, it attempts a 1 -> 0 transition and returns the
>   * success thereof.
>   *
> @@ -178,6 +232,8 @@ EXPORT_SYMBOL_GPL(refcount_dec);
>   * It can be used like a try-delete operator; this explicit case is provided
>   * and not cmpxchg in generic, because that would allow implementing unsafe
>   * operations.
> + *
> + * Return: true if the 1 -> 0 transition was successful, false otherwise

I'd formulate it differently, to match dec_and_test, return true if 0.

>   */
>  bool refcount_dec_if_one(refcount_t *r)
>  {
> @@ -185,11 +241,16 @@ bool refcount_dec_if_one(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_dec_if_one);

WARNING: multiple messages have this Message-ID (diff)
From: Peter Zijlstra <peterz@infradead.org>
To: David Windsor <dwindsor@gmail.com>
Cc: mingo@kernel.org, elena.reshetova@intel.com,
	linux-kernel@vger.kernel.org,
	kernel-hardening@lists.openwall.com
Subject: Re: [PATCH] refcount: add refcount_t API kernel-doc comments
Date: Wed, 1 Mar 2017 09:47:50 +0100	[thread overview]
Message-ID: <20170301084750.GY6515@twins.programming.kicks-ass.net> (raw)
In-Reply-To: <1488339285-23777-1-git-send-email-dwindsor@gmail.com>

On Tue, Feb 28, 2017 at 10:34:45PM -0500, David Windsor wrote:

> diff --git a/lib/refcount.c b/lib/refcount.c
> index 1d33366..30e0927 100644
> --- a/lib/refcount.c
> +++ b/lib/refcount.c
> @@ -37,6 +37,15 @@
>  #include <linux/refcount.h>
>  #include <linux/bug.h>
>  
> +/**
> + * refcount_add_not_zero - add a value to a refcount unless the refcount is 0
> + * @i: the value to add to the refcount
> + * @r: the refcount
> + *
> + * Will saturate at UINT_MAX and WARN.
> + *
> + * Return: false if the refcount is 0, true otherwise.
> + */
>  bool refcount_add_not_zero(unsigned int i, refcount_t *r)
>  {
>  	unsigned int old, new, val = atomic_read(&r->refs);
> @@ -64,18 +73,30 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_add_not_zero);
>  
> +/**
> + * refcount_add - add a value to a refcount
> + * @i: the value to add to the refcount
> + * @r: the refcount
> + *
> + * Similar to atomic_add(), will saturate at UINT_MAX and WARN.
> + */
>  void refcount_add(unsigned int i, refcount_t *r)
>  {
>  	WARN(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n");
>  }
>  EXPORT_SYMBOL_GPL(refcount_add);

Usage of both of these should be discouraged, add/sub on refcounts is
'odd'. Also, both these lack the comment on memory ordering, copy/paste
from inc_not_zero/inc.

> -/*
> +/**
> + * refcount_inc_not_zero - increment a refcount unless it is 0
> + * @r: the refcount to increment
> + *
>   * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN.
>   *
>   * Provides no memory ordering, it is assumed the caller has guaranteed the
>   * object memory to be stable (RCU, etc.). It does provide a control dependency
>   * and thereby orders future stores. See the comment on top.
> + *
> + * Return: false if the refcount is 0, true otherwise

An alternative interpretation is: return true if the increment happened,
false otherwise. But given the saturation semantics that might be
awkward, but its the one I find easier to work with.

>   */
>  bool refcount_inc_not_zero(refcount_t *r)
>  {
> @@ -103,11 +124,16 @@ bool refcount_inc_not_zero(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_inc_not_zero);
>  
> -/*
> +/**
> + * refcount_inc - increment a refcount
> + * @r: the refcount to increment
> + *
>   * Similar to atomic_inc(), will saturate at UINT_MAX and WARN.
>   *
>   * Provides no memory ordering, it is assumed the caller already has a
>   * reference on the object, will WARN when this is not so.
> + *
> + * Will WARN if refcount is 0.

I think that duplicates the final part of the prior sentence in intent.

Also, it might be useful to explain why.

>   */
>  void refcount_inc(refcount_t *r)
>  {
> @@ -115,6 +141,22 @@ void refcount_inc(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_inc);
>  
> +/**
> + * refcount_sub_and_test - subtract from a refcount and test if it is 0
> + * @i: amount to subtract from the refcount
> + * @r: the refcount
> + *
> + * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
> + * decrement when saturated at UINT_MAX.

It will equally fail the subtraction on underflow and return false
(didn't hit 0) and leak.

> + *
> + * Provides release memory ordering, such that prior loads and stores are done
> + * before, and provides a control dependency such that free() must come after.
> + * See the comment on top.
> + *
> + * Return: true if the resulting refcount is greater than 0, false if the
> + * resulting refcount is 0, the refcount is saturated at UINT_MAX or the
> + * subtraction operation causes an underflow.

I think you got that wrong, will return true when we hit 0, false
otherwise.

Remember; one writes:

	if (dec_and_test(&obj->ref))
		free(obj);

> + */
>  bool refcount_sub_and_test(unsigned int i, refcount_t *r)
>  {
>  	unsigned int old, new, val = atomic_read(&r->refs);
> @@ -140,13 +182,20 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_sub_and_test);

As with add, sub should be discouraged.

> -/*
> +/**
> + * refcount_dec_and_test - decrement a refcount and test if it is 0
> + * @r: the refcount
> + *
>   * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
>   * decrement when saturated at UINT_MAX.
>   *
>   * Provides release memory ordering, such that prior loads and stores are done
>   * before, and provides a control dependency such that free() must come after.
>   * See the comment on top.
> + *
> + * Return: true if the resulting refcount is greater than 0, false if the
> + * resulting refcount is 0, the refcount is saturated at UINT_MAX or the
> + * decrement operation causes an underflow.

got that similarly wrong.

>   */
>  bool refcount_dec_and_test(refcount_t *r)
>  {
> @@ -154,21 +203,26 @@ bool refcount_dec_and_test(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_dec_and_test);
>  
> -/*
> +/**
> + * refcount_dec - decrement a refcount
> + * @r: the refcount
> + *
>   * Similar to atomic_dec(), it will WARN on underflow and fail to decrement
>   * when saturated at UINT_MAX.
>   *
>   * Provides release memory ordering, such that prior loads and stores are done
>   * before.
>   */
> -
>  void refcount_dec(refcount_t *r)
>  {
>  	WARN(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n");
>  }
>  EXPORT_SYMBOL_GPL(refcount_dec);
>  
> -/*
> +/**
> + * refcount_dec_if_one - decrement a refcount if it is 1
> + * @r: the refcount
> + *
>   * No atomic_t counterpart, it attempts a 1 -> 0 transition and returns the
>   * success thereof.
>   *
> @@ -178,6 +232,8 @@ EXPORT_SYMBOL_GPL(refcount_dec);
>   * It can be used like a try-delete operator; this explicit case is provided
>   * and not cmpxchg in generic, because that would allow implementing unsafe
>   * operations.
> + *
> + * Return: true if the 1 -> 0 transition was successful, false otherwise

I'd formulate it differently, to match dec_and_test, return true if 0.

>   */
>  bool refcount_dec_if_one(refcount_t *r)
>  {
> @@ -185,11 +241,16 @@ bool refcount_dec_if_one(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(refcount_dec_if_one);

  parent reply	other threads:[~2017-03-01  8:47 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-01  3:34 [kernel-hardening] [PATCH] refcount: add refcount_t API kernel-doc comments David Windsor
2017-03-01  3:34 ` David Windsor
2017-03-01  5:44 ` [kernel-hardening] " Kees Cook
2017-03-01  8:48   ` Peter Zijlstra
2017-03-01  7:38 ` [kernel-hardening] " Ingo Molnar
2017-03-01  7:38   ` Ingo Molnar
2017-03-01  8:47 ` Peter Zijlstra [this message]
2017-03-01  8:47   ` Peter Zijlstra
  -- strict thread matches above, loose matches on Subject: below --
2017-03-03  1:55 [kernel-hardening] " David Windsor
2017-03-10  7:25 ` [kernel-hardening] " Ingo Molnar
2017-02-07 23:56 [kernel-hardening] " David Windsor
2017-02-08  0:49 ` [kernel-hardening] " Kees Cook
2017-02-10 14:44   ` David Windsor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170301084750.GY6515@twins.programming.kicks-ass.net \
    --to=peterz@infradead.org \
    --cc=dwindsor@gmail.com \
    --cc=elena.reshetova@intel.com \
    --cc=kernel-hardening@lists.openwall.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.