Difference between revisions of "Kernel Protections/refcount t"

From Linux Kernel Security Subsystem
Jump to navigation Jump to search
m (Minor language change in Reference Counting API)
(Change <tt> tags to <code>)
Line 5: Line 5:
= Reference Counting API =
= Reference Counting API =


HARDENED_ATOMIC introduces a new data type: <tt>refcount_t</tt>.  This type is to be used for all kernel reference counters.   
HARDENED_ATOMIC introduces a new data type: <code>refcount_t</code>.  This type is to be used for all kernel reference counters.   


The following is the kernel reference counting API.  Please note that all operations are atomic, unless otherwise specified.  
The following is the kernel reference counting API.  Please note that all operations are atomic, unless otherwise specified.  


;'''<tt>REFCOUNT_INIT(unsigned int)</tt>'''
;'''<code>REFCOUNT_INIT(unsigned int)</code>'''
: Initialize a <tt>refcount_t</tt> object.
: Initialize a <code>refcount_t</code> object.


;'''<tt>void refcount_set(refcount_t *, unsigned int)</tt>'''
;'''<code>void refcount_set(refcount_t *, unsigned int)</code>'''
: Set a <tt>refcount_t</tt> object's internal value.
: Set a <code>refcount_t</code> object's internal value.


;'''<tt>unsigned int refcount_read(refcount_t *)</tt>'''
;'''<code>unsigned int refcount_read(refcount_t *)</code>'''
: Returns the <tt>refcount_t</tt> object's internal value.
: Returns the <code>refcount_t</code> object's internal value.


;'''<tt>bool refcount_add_not_zero(unsigned int v, refcount_t *r)</tt>'''
;'''<code>bool refcount_add_not_zero(unsigned int v, refcount_t *r)</code>'''
: Add <tt>v</tt> to <tt>r</tt>.  If <tt>r + v</tt> causes an overflow, the result of the addition operation is not saved to <tt>r</tt>.  Returns <tt>true</tt> if the resulting value of <tt>r</tt> is non-zero, <tt>false</tt> otherwise.
: Add <code>v</code> to <code>r</code>.  If <code>r + v</code> causes an overflow, the result of the addition operation is not saved to <code>r</code>.  Returns <code>true</code> if the resulting value of <code>r</code> is non-zero, <code>false</code> otherwise.


;'''<tt>void refcount_add(unsigned int v, refcount_t *r)</tt>'''
;'''<code>void refcount_add(unsigned int v, refcount_t *r)</code>'''
: Adds <tt>v</tt> to <tt>r</tt> and stores the value in <tt>r</tt>.
: Adds <code>v</code> to <code>r</code> and stores the value in <code>r</code>.


;'''<tt>bool refcount_inc_not_zero(refcount_t *r)</tt>'''
;'''<code>bool refcount_inc_not_zero(refcount_t *r)</code>'''
: Increments <tt>r</tt> and tests whether <tt>r + 1</tt> causes an overflow.  If an overflow does occur, the result of the increment operation is not saved to <tt>r</tt>.  Will saturate at <tt>UINT_MAX</tt> and <tt>WARN</tt>. Returns <tt>true</tt> if the resulting value of <tt>r</tt> is non-zero, <tt>false</tt> otherwise.   
: Increments <code>r</code> and tests whether <code>r + 1</code> causes an overflow.  If an overflow does occur, the result of the increment operation is not saved to <code>r</code>.  Will saturate at <code>UINT_MAX</code> and <code>WARN</code>. Returns <code>true</code> if the resulting value of <code>r</code> is non-zero, <code>false</code> otherwise.   


;'''<tt>void refcount_inc(refcount_t *r)</tt>'''
;'''<code>void refcount_inc(refcount_t *r)</code>'''
: Increment <tt>r</tt>.  Will saturate at <tt>UINT_MAX</tt> and <tt>WARN</tt>.
: Increment <code>r</code>.  Will saturate at <code>UINT_MAX</code> and <code>WARN</code>.


;'''<tt>bool refcount_sub_and_test(unsigned int v, refcount_t *r)</tt>'''
;'''<code>bool refcount_sub_and_test(unsigned int v, refcount_t *r)</code>'''
: Subtract <tt>v</tt> from <tt>r</tt> and tests whether <tt>r - v</tt> causes an underflow.  If an underflow does occur, the result of the decrement operation is not saved to <tt>r</tt>.  Will fail to decrement when saturated at <tt>UINT_MAX</tt>.  Returns <tt>true</tt> if the resulting value of <tt>r</tt> is non-zero, <tt>false</tt> otherwise.
: Subtract <code>v</code> from <code>r</code> and tests whether <code>r - v</code> causes an underflow.  If an underflow does occur, the result of the decrement operation is not saved to <code>r</code>.  Will fail to decrement when saturated at <code>UINT_MAX</code>.  Returns <code>true</code> if the resulting value of <code>r</code> is non-zero, <code>false</code> otherwise.


;'''<tt>void refcount_dec(refcount_t *r)</tt>'''
;'''<code>void refcount_dec(refcount_t *r)</code>'''
: Decrement <tt>r</tt>.  If <tt>r - 1</tt> causes an underflow, the result of the decrement operation is not saved to <tt>r</tt>.  Will fail to decrement when saturated at <tt>UINT_MAX</tt>.
: Decrement <code>r</code>.  If <code>r - 1</code> causes an underflow, the result of the decrement operation is not saved to <code>r</code>.  Will fail to decrement when saturated at <code>UINT_MAX</code>.


;'''<tt>bool refcount_dec_if_one(refcount_t *r)</tt>'''
;'''<code>bool refcount_dec_if_one(refcount_t *r)</code>'''
: Attempts to transition <tt>r</tt> from 1 to 0.  If <tt>r</tt> is 1, decrement it to 0.  Returns <tt>true</tt> if <tt>r</tt> was decremented, <tt>false</tt> otherwise.   
: Attempts to transition <code>r</code> from 1 to 0.  If <code>r</code> is 1, decrement it to 0.  Returns <code>true</code> if <code>r</code> was decremented, <code>false</code> otherwise.   


;'''<tt>bool refcount_dec_not_one(refcount_t *r)</tt>'''
;'''<code>bool refcount_dec_not_one(refcount_t *r)</code>'''
: Decrement <tt>r</tt> unless the value of <tt>r</tt> is 1.  Returns <tt>true</tt> if <tt>r</tt> was decremented, </tt>false</tt> otherwise.
: Decrement <code>r</code> unless the value of <code>r</code> is 1.  Returns <code>true</code> if <code>r</code> was decremented, </code>false</code> otherwise.


;'''<tt>bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock)</tt>'''
;'''<code>bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock)</code>'''
: Decrement <tt>r</tt> and lock mutex if <tt>r</tt> becomes 0.  Will <tt>WARN</tt> on underflow and fail to decrement if <tt>r</tt> is saturated at <tt>UINT_MAX</tt>.  Returns <tt>true</tt> if <tt>r</tt> is 0 and mutex is held, <tt>false</tt> otherwise.
: Decrement <code>r</code> and lock mutex if <code>r</code> becomes 0.  Will <code>WARN</code> on underflow and fail to decrement if <code>r</code> is saturated at <code>UINT_MAX</code>.  Returns <code>true</code> if <code>r</code> is 0 and mutex is held, <code>false</code> otherwise.


;'''<tt>bool refcount_dec_and_lock(refcount_t *r, spinlock_t *s)</tt>'''
;'''<code>bool refcount_dec_and_lock(refcount_t *r, spinlock_t *s)</code>'''
: Decrement <tt>r</tt> and lock spinlock if <tt>r</tt> becomes 0.  Will <tt>WARN</tt> on underflow and fail to decrement if <tt>r</tt> is saturated at <tt>UINT_MAX</tt>.  Returns <tt>true</tt> if <tt>r</tt> is 0 and spinlock is held, <tt>false</tt> otherwise.
: Decrement <code>r</code> and lock spinlock if <code>r</code> becomes 0.  Will <code>WARN</code> on underflow and fail to decrement if <code>r</code> is saturated at <code>UINT_MAX</code>.  Returns <code>true</code> if <code>r</code> is 0 and spinlock is held, <code>false</code> otherwise.

Revision as of 12:19, 6 February 2017

Summary

HARDENED_ATOMIC is a kernel self-protection mechanism that greatly helps with the mitigation of use-after-free bugs. It is based off of work done by the PaX Team, originally called PAX_REFCOUNT.

Reference Counting API

HARDENED_ATOMIC introduces a new data type: refcount_t. This type is to be used for all kernel reference counters.

The following is the kernel reference counting API. Please note that all operations are atomic, unless otherwise specified.

REFCOUNT_INIT(unsigned int)
Initialize a refcount_t object.
void refcount_set(refcount_t *, unsigned int)
Set a refcount_t object's internal value.
unsigned int refcount_read(refcount_t *)
Returns the refcount_t object's internal value.
bool refcount_add_not_zero(unsigned int v, refcount_t *r)
Add v to r. If r + v causes an overflow, the result of the addition operation is not saved to r. Returns true if the resulting value of r is non-zero, false otherwise.
void refcount_add(unsigned int v, refcount_t *r)
Adds v to r and stores the value in r.
bool refcount_inc_not_zero(refcount_t *r)
Increments r and tests whether r + 1 causes an overflow. If an overflow does occur, the result of the increment operation is not saved to r. Will saturate at UINT_MAX and WARN. Returns true if the resulting value of r is non-zero, false otherwise.
void refcount_inc(refcount_t *r)
Increment r. Will saturate at UINT_MAX and WARN.
bool refcount_sub_and_test(unsigned int v, refcount_t *r)
Subtract v from r and tests whether r - v causes an underflow. If an underflow does occur, the result of the decrement operation is not saved to r. Will fail to decrement when saturated at UINT_MAX. Returns true if the resulting value of r is non-zero, false otherwise.
void refcount_dec(refcount_t *r)
Decrement r. If r - 1 causes an underflow, the result of the decrement operation is not saved to r. Will fail to decrement when saturated at UINT_MAX.
bool refcount_dec_if_one(refcount_t *r)
Attempts to transition r from 1 to 0. If r is 1, decrement it to 0. Returns true if r was decremented, false otherwise.
bool refcount_dec_not_one(refcount_t *r)
Decrement r unless the value of r is 1. Returns true if r was decremented, false otherwise.
bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock)
Decrement r and lock mutex if r becomes 0. Will WARN on underflow and fail to decrement if r is saturated at UINT_MAX. Returns true if r is 0 and mutex is held, false otherwise.
bool refcount_dec_and_lock(refcount_t *r, spinlock_t *s)
Decrement r and lock spinlock if r becomes 0. Will WARN on underflow and fail to decrement if r is saturated at UINT_MAX. Returns true if r is 0 and spinlock is held, false otherwise.