However, since a tasks credentials are generally not changed very often, we canreasonably make use of a loop involving reading the creds pointer and usingatomic_inc_not_zero() to attempt to increment it if it hasn't already hit zero.

If successful, we can safely return the credentials in the knowledge that, evenif the task we're accessing has released them, they haven't gone to the RCUcleanup code.

We then change task_state() in procfs to use get_task_cred() rather thancalling get_cred() on the result of __task_cred(), as that suffers from thesame problem.

Without this change, a BUG_ON in __put_cred() or in put_cred_rcu() can betripped when it is noticed that the usage count is not zero as it ought to be,for example:

+/**+ * get_task_cred - Get another task's objective credentials+ * @task: The task to query+ *+ * Get the objective credentials of a task, pinning them so that they can't go+ * away. Accessing a task's credentials directly is not permitted.+ *+ * The caller must also make sure task doesn't get deleted, either by holding a+ * ref on task or by holding tasklist_lock to prevent it from being unlinked.+ */+const struct cred *get_task_cred(struct task_struct *task)+{+ const struct cred *cred;++ rcu_read_lock();++ do {+ cred = __task_cred((task));+ BUG_ON(!cred);+ } while (!atomic_inc_not_zero(&((struct cred *)cred)->usage));++ rcu_read_unlock();+ return cred;+}+ /* * Allocate blank credentials, such that the credentials can be filled in at a * later date without risk of ENOMEM.-- 1.7.4.4