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
Last revision Both sides next revision
arm_kernel_panic [2018/11/28 12:55]
rpjday [Disassembling ''futex_wait_setup'']
arm_kernel_panic [2018/11/28 13:02]
rpjday [The kernel panic]
Line 29: Line 29:
   * register ''​r5''​ contains the value ''​00000002''​   * register ''​r5''​ contains the value ''​00000002''​
  
 +===== The offending(?​) kernbel 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