Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
arm_kernel_panic [2018/11/28 12:55] – [Disassembling ''futex_wait_setup''] rpjdayarm_kernel_panic [2018/11/28 13:02] (current) – [The offending(?) kernbel code] rpjday
Line 29: Line 29:
   * register ''r5'' contains the value ''00000002''   * register ''r5'' contains the value ''00000002''
  
 +===== The offending(?) kernel code =====
 +
 +From ''kernel/futex.c'':
 +
 +<code>
 +/* The key must be already stored in q->key. */
 +static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
 +        __acquires(&hb->lock)
 +{
 +        struct futex_hash_bucket *hb;
 +
 +        hb = hash_futex(&q->key);
 +
 +        /*
 +         * Increment the counter before taking the lock so that
 +         * a potential waker won't miss a to-be-slept task that is
 +         * waiting for the spinlock. This is safe as all queue_lock()
 +         * users end up calling queue_me(). Similarly, for housekeeping,
 +         * decrement the counter at queue_unlock() when some error has
 +         * occurred and we don't end up adding the task to the list.
 +         */
 +        hb_waiters_inc(hb);
 +
 +        q->lock_ptr = &hb->lock;
 +
 +        spin_lock(&hb->lock); /* implies MB (A) */
 +        return hb;
 +}
 +</code>
 +
 +<code>
 +/**
 + * futex_wait_setup() - Prepare to wait on a futex
 + * @uaddr:      the futex userspace address
 + * @val:        the expected value 
 + * @flags:      futex flags (FLAGS_SHARED, etc.)
 + * @q:          the associated futex_q
 + * @hb:         storage for hash_bucket pointer to be returned to caller
 + *
 + * Setup the futex_q and locate the hash_bucket.  Get the futex value and
 + * compare it with the expected value.  Handle atomic faults internally.
 + * Return with the hb lock held and a q.key reference on success, and unlocked
 + * with no q.key reference on failure.
 + *
 + * Return:
 +  0 - uaddr contains val and hb has been locked;
 + * <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlocked
 + */
 +static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
 +                           struct futex_q *q, struct futex_hash_bucket **hb)
 +{
 +        u32 uval;
 +        int ret;
 +
 +        /*
 +         * Access the page AFTER the hash-bucket is locked.
 +         * Order is important:
 +         *
 +           Userspace waiter: val = var; if (cond(val)) futex_wait(&var, val);
 +           Userspace waker:  if (cond(var)) { var = new; futex_wake(&var); }
 +         *
 +         * The basic logical guarantee of a futex is that it blocks ONLY
 +         * if cond(var) is known to be true at the time of blocking, for
 +         * any cond.  If we locked the hash-bucket after testing *uaddr, that
 +         * would open a race condition where we could block indefinitely with
 +         * cond(var) false, which would violate the guarantee.
 +              
 +         * On the other hand, we insert q and release the hash-bucket only
 +         * after testing *uaddr.  This guarantees that futex_wait() will NOT
 +         * absorb a wakeup if *uaddr does not match the desired values
 +         * while the syscall executes.
 +         */
 +retry:
 +        ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ);
 +        if (unlikely(ret != 0))
 +                return ret;
 + 
 +retry_private:
 +        *hb = queue_lock(q);
 +
 +        ret = get_futex_value_locked(&uval, uaddr);
 +
 +        if (ret) {
 +                queue_unlock(*hb);
 +
 +                ret = get_user(uval, uaddr);
 +                if (ret)
 +                        goto out;
 +
 +                if (!(flags & FLAGS_SHARED))
 +                        goto retry_private;
 +
 +                put_futex_key(&q->key);
 +                goto retry;
 +        }
 +
 +        if (uval != val) {
 +                queue_unlock(*hb);
 +                ret = -EWOULDBLOCK;
 +        }
 +
 +out:
 +        if (ret)
 +                put_futex_key(&q->key);
 +        return ret;
 +}
 +</code>
 ===== Disassembling ''futex_wait_setup'' ===== ===== Disassembling ''futex_wait_setup'' =====
  
  • arm_kernel_panic.1543409737.txt.gz
  • Last modified: 2018/11/28 12:55
  • by rpjday