linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] apparmor: remove the "task" arg from may_change_ptraced_domain()
@ 2013-09-16 14:20 Oleg Nesterov
  2013-09-16 15:10 ` Oleg Nesterov
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Oleg Nesterov @ 2013-09-16 14:20 UTC (permalink / raw)
  To: John Johansen; +Cc: Richard Guy Briggs, linux-kernel

Unless task == current ptrace_parent(task) is not safe even under
rcu_read_lock() and most of the current users are not right.

So may_change_ptraced_domain(task) looks wrong as well. However it
is always called with task == current so the code is actually fine.
Remove this argument to make this fact clear.

Note: perhaps we should simply kill ptrace_parent(), it buys almost
nothing. And it is obviously racy, perhaps this should be fixed.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 security/apparmor/domain.c |   14 ++++++--------
 1 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 26c607c..8423558 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -50,23 +50,21 @@ void aa_free_domain_entries(struct aa_domain *domain)
 
 /**
  * may_change_ptraced_domain - check if can change profile on ptraced task
- * @task: task we want to change profile of   (NOT NULL)
  * @to_profile: profile to change to  (NOT NULL)
  *
- * Check if the task is ptraced and if so if the tracing task is allowed
+ * Check if current is ptraced and if so if the tracing task is allowed
  * to trace the new domain
  *
  * Returns: %0 or error if change not allowed
  */
-static int may_change_ptraced_domain(struct task_struct *task,
-				     struct aa_profile *to_profile)
+static int may_change_ptraced_domain(struct aa_profile *to_profile)
 {
 	struct task_struct *tracer;
 	struct aa_profile *tracerp = NULL;
 	int error = 0;
 
 	rcu_read_lock();
-	tracer = ptrace_parent(task);
+	tracer = ptrace_parent(current);
 	if (tracer)
 		/* released below */
 		tracerp = aa_get_task_profile(tracer);
@@ -477,7 +475,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
 	}
 
 	if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
-		error = may_change_ptraced_domain(current, new_profile);
+		error = may_change_ptraced_domain(new_profile);
 		if (error) {
 			aa_put_profile(new_profile);
 			goto audit;
@@ -690,7 +688,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
 			}
 		}
 
-		error = may_change_ptraced_domain(current, hat);
+		error = may_change_ptraced_domain(hat);
 		if (error) {
 			info = "ptraced";
 			error = -EPERM;
@@ -829,7 +827,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
 	}
 
 	/* check if tracing task is allowed to trace target domain */
-	error = may_change_ptraced_domain(current, target);
+	error = may_change_ptraced_domain(target);
 	if (error) {
 		info = "ptrace prevents transition";
 		goto audit;
-- 
1.5.5.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread
* (no subject)
@ 2013-12-18 19:43 Richard Guy Briggs
  2013-12-18 20:19 ` [PATCH] apparmor: remove the "task" arg from may_change_ptraced_domain() Oleg Nesterov
  0 siblings, 1 reply; 10+ messages in thread
From: Richard Guy Briggs @ 2013-12-18 19:43 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: John Johansen, Andrew Morton, Eric W. Biederman, Eric Paris,
	linux-kernel

Bcc: rgb@redhat.com
Subject: Re: [PATCH] apparmor: remove the "task" arg from
 may_change_ptraced_domain()
Reply-To: 
In-Reply-To: <20130926132519.GY13968@madcap2.tricolour.ca>

On 13/09/26, Richard Guy Briggs wrote:
> On Tue, Sep 24, 2013 at 06:44:42PM +0200, Oleg Nesterov wrote:
> > On 09/23, Richard Guy Briggs wrote:
> > >
> > > On Mon, Sep 16, 2013 at 04:20:35PM +0200, Oleg Nesterov wrote:
> > > > Unless task == current ptrace_parent(task) is not safe even under
> > > > rcu_read_lock() and most of the current users are not right.
> > >
> > > Could you point to an explanation of this?
> > 
> > If this task exits before rcu_read_lock() ->parent can point to the
> > already freed/reused memory.
> 
> Ok, understood.  So even though the task may have exited, the task
> struct pointer is still valid, but not the contents of the task struct
> to which it points.

[The thread also relates to the patch
	"pid: get ppid pid_t of task in init_pid_ns safely"
in which sys_getppid() (which appears safe) is replaced with something that
references the init_pid_ns rather than current's pid_ns.]

So, in the general case, that call is not safe, and we should at least
remove the task_struct argument.

Analysing the calling tree, I see that most callers just call with
"current" anyways.  (Read this tree as "is called by" with the provided
"struct task_struct *".)

audit_log_task_info(?)
        audit_log_link_denied(current)
        audit_log_exit(?)
		__audit_free(?)
			audit_free(?)
                		do_exit(current)
        		        copy_process(?)
					[see below]
        ima_audit_measurement(current)
audit_filter_rules(?)
        audit_filter_task(?)
                audit_alloc(?)
			copy_process(?)
				p->real_parent is copy of current->real_parent
        audit_filter_syscall(?)
                audit_get_context(?)
                __audit_syscall_entry(current)
        audit_filter_inode_name(?)
                audit_filter_inodes(?)
                        audit_update_watch(current)
                        audit_get_context(?)
                                __audit_free(?)
                                        audit_free(?)
                                                do_exit(current)
                                                copy_process(?)
							[see below]
                                __audit_syscall_exit(current)

So looking further at copy_process()... 

	copy_flags() looks weird.  The clone_flags parameter is not used.  The
	existing flags (copied from the parent in dup_task_struct()) are
	massaged, removing PF_SUPERPRIV and PF_WQ_WORKER and adding
	PF_FORKNOEXEC.

	copy_process() passes an identical copy of "current" to audit_alloc()
	(as far as task_struct::real_parent is concerned).

	copy_process() passes an identical copy of "current" to audit_free()
	(as far as task_struct::real_parent is concerned) in all cases
	*except* if the original process has a signal_pending() and
	copy_process() was called without CLONE_PARENT or CLONE_THREAD, in
	which case tsk->real_parent is actually current.

	In fact, the actions listed in the true clause of:
		"if (clone_flags & (CLONE_PARENT|CLONE_THREAD))"
	look redundant.

So, can audit_log_task_info() and audit_filter_rules() be fixed to be called
without the task_struct pointer and just use current->real_parent directly?
How do we check for the case where there was a signal pending it and
tsk->real_parent now equals "current"?

> > (in the long term we should probably clear
> >  ->parent/real_parent/group_leader/more in __unhash_process(), but
> >  lets not discuss this right now ;)
> 
> ...so that the contents are valid in a task struct of a task that has
> exited.

The assumptions made above include that sys_getppid() was safe all along.

> Thanks for the (more obvious to me now) explanation.
> 
> > Oleg.
> 
> - RGB

- RGB

--
Richard Guy Briggs <rbriggs@redhat.com>
Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-12-20 17:59 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-16 14:20 [PATCH] apparmor: remove the "task" arg from may_change_ptraced_domain() Oleg Nesterov
2013-09-16 15:10 ` Oleg Nesterov
2013-09-16 17:01 ` John Johansen
2013-09-23 21:52 ` Richard Guy Briggs
2013-09-24 16:44   ` Oleg Nesterov
2013-09-26 13:25     ` Richard Guy Briggs
  -- strict thread matches above, loose matches on Subject: below --
2013-12-18 19:43 Richard Guy Briggs
2013-12-18 20:19 ` [PATCH] apparmor: remove the "task" arg from may_change_ptraced_domain() Oleg Nesterov
2013-12-20  4:36   ` Richard Guy Briggs
2013-12-20  6:22     ` John Johansen
2013-12-20 17:59     ` Oleg Nesterov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).