lkml.org 
[lkml]   [2017]   [Oct]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 02/15] sched: convert signal_struct.sigcnt to refcount_t
    Date
    atomic_t variables are currently used to implement reference
    counters with the following properties:
    - counter is initialized to 1 using atomic_set()
    - a resource is freed upon counter reaching zero
    - once counter reaches zero, its further
    increments aren't allowed
    - counter schema uses basic atomic operations
    (set, inc, inc_not_zero, dec_and_test, etc.)

    Such atomic variables should be converted to a newly provided
    refcount_t type and API that prevents accidental counter overflows
    and underflows. This is important since overflows and underflows
    can lead to use-after-free situation and be exploitable.

    The variable signal_struct.sigcnt is used as pure reference counter.
    Convert it to refcount_t and fix up the operations.

    Suggested-by: Kees Cook <keescook@chromium.org>
    Reviewed-by: David Windsor <dwindsor@gmail.com>
    Reviewed-by: Hans Liljestrand <ishkamiel@gmail.com>
    Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
    ---
    include/linux/sched/signal.h | 2 +-
    kernel/fork.c | 6 +++---
    2 files changed, 4 insertions(+), 4 deletions(-)

    diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
    index b40fbf7..856d957 100644
    --- a/include/linux/sched/signal.h
    +++ b/include/linux/sched/signal.h
    @@ -77,7 +77,7 @@ struct thread_group_cputimer {
    * the locking of signal_struct.
    */
    struct signal_struct {
    - atomic_t sigcnt;
    + refcount_t sigcnt;
    atomic_t live;
    int nr_threads;
    struct list_head thread_head;
    diff --git a/kernel/fork.c b/kernel/fork.c
    index ab4ddc9..869850b 100644
    --- a/kernel/fork.c
    +++ b/kernel/fork.c
    @@ -642,7 +642,7 @@ static inline void free_signal_struct(struct signal_struct *sig)

    static inline void put_signal_struct(struct signal_struct *sig)
    {
    - if (atomic_dec_and_test(&sig->sigcnt))
    + if (refcount_dec_and_test(&sig->sigcnt))
    free_signal_struct(sig);
    }

    @@ -1443,7 +1443,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)

    sig->nr_threads = 1;
    atomic_set(&sig->live, 1);
    - atomic_set(&sig->sigcnt, 1);
    + refcount_set(&sig->sigcnt, 1);

    /* list_add(thread_node, thread_head) without INIT_LIST_HEAD() */
    sig->thread_head = (struct list_head)LIST_HEAD_INIT(tsk->thread_node);
    @@ -1950,7 +1950,7 @@ static __latent_entropy struct task_struct *copy_process(
    } else {
    current->signal->nr_threads++;
    atomic_inc(&current->signal->live);
    - atomic_inc(&current->signal->sigcnt);
    + refcount_inc(&current->signal->sigcnt);
    list_add_tail_rcu(&p->thread_group,
    &p->group_leader->thread_group);
    list_add_tail_rcu(&p->thread_node,
    --
    2.7.4
    \
     
     \ /
      Last update: 2017-10-22 17:39    [W:4.163 / U:0.392 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site