Locking in AppArmor
===================

Lock hierarchy:

	aa_interface_lock
	  profile_list_lock
	    aa_profile->lock
	      task_lock()


Which lock protects what?

	/-----------------------+-------------------------------\
	| Variable		| Lock				|
	>-----------------------+-------------------------------<
	| profile_list		| profile_list_lock		|
	+-----------------------+-------------------------------+
	| aa_profile		| (reference count)		|
	+-----------------------+-------------------------------+
	| aa_profile->		| aa_profile->lock		|
	|   isstale,		|				|
	|   task_contexts	|				|
	+-----------------------+-------------------------------+
	| task_struct->security	| read: RCU			|
	|			| write: task_lock()		|
	+-----------------------+-------------------------------+
	| aa_profile->sub	| handle on the profile (list	|
	|			| is never modified)		|
	\-----------------------+-------------------------------/

(Obviously, the list_heads embedded in data structures are always
protected with the lock that also protects the list.)

When moving a task context from one profile to another, we grab both
profile locks with lock_both_profiles(). This ensures that both locks
are always taken in the same order, and so we won't deadlock.

Since task_struct->security is RCU protected the aa_task_struct it
references is only guarenteed to exist for the rcu cycle.  Where
aa_task_context->profile is needed in blocking operations the
profile's reference count is incremented and the profile reference
is used.

Profiles on profile_list are never stale: when a profile becomes stale,
it is removed from profile_list at the same time (under profile_list_lock
and aa_profile->lock).

The aa_interface_lock is taken whenever user-space modifies the profile
list, and can sleep. This ensures that profile loading/replacement/removal
won't race with itself. We release the profile_list_lock as soon as
possible to avoid stalling exec during profile loading/replacement/removal.

lock_dep reports a false 'possible irq lock inversion dependency detected'
when the profile lock is taken in aa_release.  This is due to that the
task_lock is often taken inside the profile lock but other kernel code
takes the task_lock with interrupts enabled.  A deadlock will not actually
occur because apparmor does not take the task_lock in hard_irq or soft_irq
context.
