User Tools

Site Tools


arm_kernel_panic

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]
rpjday [Disassembling ''futex_wait_setup'']
arm_kernel_panic [2018/11/28 13:02]
rpjday [The offending(?) kernbel code]
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.txt ยท Last modified: 2018/11/28 13:02 by rpjday