svn commit: r277698 - in stable/10: lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys

Konstantin Belousov kib at FreeBSD.org
Sun Jan 25 13:15:15 UTC 2015


Author: kib
Date: Sun Jan 25 13:15:12 2015
New Revision: 277698
URL: https://svnweb.freebsd.org/changeset/base/277698

Log:
  MFC r277322:
  Add procctl(2) PROC_TRACE_CTL command to enable or disable debugger
  attachment to the process.

Modified:
  stable/10/lib/libc/sys/procctl.2
  stable/10/sys/compat/freebsd32/freebsd32_misc.c
  stable/10/sys/kern/kern_exec.c
  stable/10/sys/kern/kern_fork.c
  stable/10/sys/kern/kern_procctl.c
  stable/10/sys/kern/kern_prot.c
  stable/10/sys/kern/kern_sig.c
  stable/10/sys/sys/priv.h
  stable/10/sys/sys/proc.h
  stable/10/sys/sys/procctl.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/lib/libc/sys/procctl.2
==============================================================================
--- stable/10/lib/libc/sys/procctl.2	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/lib/libc/sys/procctl.2	Sun Jan 25 13:15:12 2015	(r277698)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 16, 2014
+.Dd December 29, 2014
 .Dt PROCCTL 2
 .Os
 .Sh NAME
@@ -275,7 +275,61 @@ delivery failed, e.g. due to the permiss
 If no such process exist, the
 .Fa rk_fpid
 field is set to -1.
+.It Dv PROC_TRACE_CTL
+Enable or disable tracing of the specified process(es), according to the
+value of the integer argument.
+Tracing includes attachment to the process using
+.Xr ptrace 2
+and
+.Xr ktrace 2 ,
+debugging sysctls,
+.Xr hwpmc 4 ,
+.Xr dtrace 1
+and core dumping.
+Possible values for the
+.Fa data
+argument are:
+.Bl -tag -width "Dv PROC_TRACE_CTL_DISABLE_EXEC"
+.It Dv PROC_TRACE_CTL_ENABLE
+Enable tracing, after it was disabled by
+.Dv PROC_TRACE_CTL_DISABLE .
+Only allowed for self.
+.It Dv PROC_TRACE_CTL_DISABLE
+Disable tracing for the specified process.
+Tracing is re-enabled when the process changes the executing
+program with
+.Xr execve 2
+syscall.
+A child inherits the trace settings from the parent on
+.Xr fork 2 .
+.It Dv PROC_TRACE_CTL_DISABLE_EXEC
+Same as
+.Dv PROC_TRACE_CTL_DISABLE ,
+but the setting persist for the process even after
+.Xr execve 2 .
+.El
+.It Dv PROC_TRACE_STATUS
+Returns the current tracing status for the specified process in
+the integer variable pointed to by
+.Fa data .
+If tracing is disabled,
+.Fa data
+is set to -1.
+If tracing is enabled, but no debugger is attached by
+.Xr ptrace 2
+syscall,
+.Fa data
+is set to 0.
+If a debugger is attached,
+.Fa data
+is set to the pid of the debugger process.
 .El
+.Sh NOTES
+Disabling tracing on a process should not be considered a security
+feature, as it is bypassable both by the kernel and privileged processes,
+and via other system mechanisms.
+As such, it should not be relied on to reliably protect cryptographic
+keying material or other confidential data.
 .Sh RETURN VALUES
 If an error occurs, a value of -1 is returned and
 .Va errno
@@ -343,11 +397,34 @@ The
 .Dv PROC_REAP_ACQUIRE
 request was issued by a process that had already acquired reaper status
 and has not yet released it.
+.It Bq Er EBUSY
+The
+.Dv PROC_TRACE_CTL
+request was issued for a process already being traced.
+.It Bq Er EPERM
+The
+.Dv PROC_TRACE_CTL
+request to re-enable tracing of the process (
+.Dv PROC_TRACE_CTL_ENABLE ) ,
+or to disable persistence of the
+.Dv PROC_TRACE_CTL_DISABLE
+on
+.Xr execve 2
+was issued for a non-current process.
+.It Bq Er EINVAL
+The value of the integer
+.Fa data
+parameter for the
+.Dv PROC_TRACE_CTL
+request is invalid.
 .El
 .Sh SEE ALSO
+.Xr dtrace 1 ,
 .Xr kill 2 ,
+.Xr ktrace 2 ,
 .Xr ptrace 2 ,
 .Xr wait 2 ,
+.Xr hwpmc 4 ,
 .Xr init 8
 .Sh HISTORY
 The

Modified: stable/10/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- stable/10/sys/compat/freebsd32/freebsd32_misc.c	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/compat/freebsd32/freebsd32_misc.c	Sun Jan 25 13:15:12 2015	(r277698)
@@ -3074,6 +3074,7 @@ freebsd32_procctl(struct thread *td, str
 
 	switch (uap->com) {
 	case PROC_SPROTECT:
+	case PROC_TRACE_CTL:
 		error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
 		if (error != 0)
 			return (error);
@@ -3102,6 +3103,9 @@ freebsd32_procctl(struct thread *td, str
 			return (error);
 		data = &x.rk;
 		break;
+	case PROC_TRACE_STATUS:
+		data = &flags;
+		break;
 	default:
 		return (EINVAL);
 	}
@@ -3117,6 +3121,10 @@ freebsd32_procctl(struct thread *td, str
 		if (error == 0)
 			error = error1;
 		break;
+	case PROC_TRACE_STATUS:
+		if (error == 0)
+			error = copyout(&flags, uap->data, sizeof(flags));
+		break;
 	}
 	return (error);
 }

Modified: stable/10/sys/kern/kern_exec.c
==============================================================================
--- stable/10/sys/kern/kern_exec.c	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/kern/kern_exec.c	Sun Jan 25 13:15:12 2015	(r277698)
@@ -658,6 +658,8 @@ interpret:
 	 * it that it now has its own resources back
 	 */
 	p->p_flag |= P_EXEC;
+	if ((p->p_flag2 & P2_NOTRACE_EXEC) == 0)
+		p->p_flag2 &= ~P2_NOTRACE;
 	if (p->p_flag & P_PPWAIT) {
 		p->p_flag &= ~(P_PPWAIT | P_PPTRACE);
 		cv_broadcast(&p->p_pwait);

Modified: stable/10/sys/kern/kern_fork.c
==============================================================================
--- stable/10/sys/kern/kern_fork.c	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/kern/kern_fork.c	Sun Jan 25 13:15:12 2015	(r277698)
@@ -501,7 +501,7 @@ do_fork(struct thread *td, int flags, st
 	 * Increase reference counts on shared objects.
 	 */
 	p2->p_flag = P_INMEM;
-	p2->p_flag2 = 0;
+	p2->p_flag2 = p1->p_flag2 & (P2_NOTRACE | P2_NOTRACE_EXEC);
 	p2->p_swtick = ticks;
 	if (p1->p_flag & P_PROFIL)
 		startprofclock(p2);

Modified: stable/10/sys/kern/kern_procctl.c
==============================================================================
--- stable/10/sys/kern/kern_procctl.c	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/kern/kern_procctl.c	Sun Jan 25 13:15:12 2015	(r277698)
@@ -280,6 +280,62 @@ reap_kill(struct thread *td, struct proc
 	return (error);
 }
 
+static int
+trace_ctl(struct thread *td, struct proc *p, int state)
+{
+
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+
+	/*
+	 * Ktrace changes p_traceflag from or to zero under the
+	 * process lock, so the test does not need to acquire ktrace
+	 * mutex.
+	 */
+	if ((p->p_flag & P_TRACED) != 0 || p->p_traceflag != 0)
+		return (EBUSY);
+
+	switch (state) {
+	case PROC_TRACE_CTL_ENABLE:
+		if (td->td_proc != p)
+			return (EPERM);
+		p->p_flag2 &= ~(P2_NOTRACE | P2_NOTRACE_EXEC);
+		break;
+	case PROC_TRACE_CTL_DISABLE_EXEC:
+		p->p_flag2 |= P2_NOTRACE_EXEC | P2_NOTRACE;
+		break;
+	case PROC_TRACE_CTL_DISABLE:
+		if ((p->p_flag2 & P2_NOTRACE_EXEC) != 0) {
+			KASSERT((p->p_flag2 & P2_NOTRACE) != 0,
+			    ("dandling P2_NOTRACE_EXEC"));
+			if (td->td_proc != p)
+				return (EPERM);
+			p->p_flag2 &= ~P2_NOTRACE_EXEC;
+		} else {
+			p->p_flag2 |= P2_NOTRACE;
+		}
+		break;
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
+
+static int
+trace_status(struct thread *td, struct proc *p, int *data)
+{
+
+	if ((p->p_flag2 & P2_NOTRACE) != 0) {
+		KASSERT((p->p_flag & P_TRACED) == 0,
+		    ("%d traced but tracing disabled", p->p_pid));
+		*data = -1;
+	} else if ((p->p_flag & P_TRACED) != 0) {
+		*data = p->p_pptr->p_pid;
+	} else {
+		*data = 0;
+	}
+	return (0);
+}
+
 #ifndef _SYS_SYSPROTO_H_
 struct procctl_args {
 	idtype_t idtype;
@@ -302,6 +358,7 @@ sys_procctl(struct thread *td, struct pr
 
 	switch (uap->com) {
 	case PROC_SPROTECT:
+	case PROC_TRACE_CTL:
 		error = copyin(uap->data, &flags, sizeof(flags));
 		if (error != 0)
 			return (error);
@@ -328,6 +385,9 @@ sys_procctl(struct thread *td, struct pr
 			return (error);
 		data = &x.rk;
 		break;
+	case PROC_TRACE_STATUS:
+		data = &flags;
+		break;
 	default:
 		return (EINVAL);
 	}
@@ -342,6 +402,10 @@ sys_procctl(struct thread *td, struct pr
 		if (error == 0)
 			error = error1;
 		break;
+	case PROC_TRACE_STATUS:
+		if (error == 0)
+			error = copyout(&flags, uap->data, sizeof(flags));
+		break;
 	}
 	return (error);
 }
@@ -364,6 +428,10 @@ kern_procctl_single(struct thread *td, s
 		return (reap_getpids(td, p, data));
 	case PROC_REAP_KILL:
 		return (reap_kill(td, p, data));
+	case PROC_TRACE_CTL:
+		return (trace_ctl(td, p, *(int *)data));
+	case PROC_TRACE_STATUS:
+		return (trace_status(td, p, data));
 	default:
 		return (EINVAL);
 	}
@@ -375,6 +443,7 @@ kern_procctl(struct thread *td, idtype_t
 	struct pgrp *pg;
 	struct proc *p;
 	int error, first_error, ok;
+	bool tree_locked;
 
 	switch (com) {
 	case PROC_REAP_ACQUIRE:
@@ -382,6 +451,7 @@ kern_procctl(struct thread *td, idtype_t
 	case PROC_REAP_STATUS:
 	case PROC_REAP_GETPIDS:
 	case PROC_REAP_KILL:
+	case PROC_TRACE_STATUS:
 		if (idtype != P_PID)
 			return (EINVAL);
 	}
@@ -391,11 +461,17 @@ kern_procctl(struct thread *td, idtype_t
 	case PROC_REAP_STATUS:
 	case PROC_REAP_GETPIDS:
 	case PROC_REAP_KILL:
+	case PROC_TRACE_CTL:
 		sx_slock(&proctree_lock);
+		tree_locked = true;
 		break;
 	case PROC_REAP_ACQUIRE:
 	case PROC_REAP_RELEASE:
 		sx_xlock(&proctree_lock);
+		tree_locked = true;
+		break;
+	case PROC_TRACE_STATUS:
+		tree_locked = false;
 		break;
 	default:
 		return (EINVAL);
@@ -456,6 +532,7 @@ kern_procctl(struct thread *td, idtype_t
 		error = EINVAL;
 		break;
 	}
-	sx_unlock(&proctree_lock);
+	if (tree_locked)
+		sx_unlock(&proctree_lock);
 	return (error);
 }

Modified: stable/10/sys/kern/kern_prot.c
==============================================================================
--- stable/10/sys/kern/kern_prot.c	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/kern/kern_prot.c	Sun Jan 25 13:15:12 2015	(r277698)
@@ -1711,6 +1711,13 @@ p_candebug(struct thread *td, struct pro
 	if ((p->p_flag & P_INEXEC) != 0)
 		return (EBUSY);
 
+	/* Denied explicitely */
+	if ((p->p_flag2 & P2_NOTRACE) != 0) {
+		error = priv_check(td, PRIV_DEBUG_DENIED);
+		if (error != 0)
+			return (error);
+	}
+
 	return (0);
 }
 

Modified: stable/10/sys/kern/kern_sig.c
==============================================================================
--- stable/10/sys/kern/kern_sig.c	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/kern/kern_sig.c	Sun Jan 25 13:15:12 2015	(r277698)
@@ -3257,7 +3257,8 @@ coredump(struct thread *td)
 	MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
 	_STOPEVENT(p, S_CORE, 0);
 
-	if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0)) {
+	if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
+	    (p->p_flag2 & P2_NOTRACE) != 0) {
 		PROC_UNLOCK(p);
 		return (EFAULT);
 	}

Modified: stable/10/sys/sys/priv.h
==============================================================================
--- stable/10/sys/sys/priv.h	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/sys/priv.h	Sun Jan 25 13:15:12 2015	(r277698)
@@ -111,6 +111,7 @@
 #define	PRIV_DEBUG_DIFFCRED	80	/* Exempt debugging other users. */
 #define	PRIV_DEBUG_SUGID	81	/* Exempt debugging setuid proc. */
 #define	PRIV_DEBUG_UNPRIV	82	/* Exempt unprivileged debug limit. */
+#define	PRIV_DEBUG_DENIED	83	/* Exempt P2_NOTRACE. */
 
 /*
  * Dtrace privileges.

Modified: stable/10/sys/sys/proc.h
==============================================================================
--- stable/10/sys/sys/proc.h	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/sys/proc.h	Sun Jan 25 13:15:12 2015	(r277698)
@@ -651,6 +651,8 @@ struct proc {
 
 /* These flags are kept in p_flag2. */
 #define	P2_INHERIT_PROTECTED 0x00000001 /* New children get P_PROTECTED. */
+#define	P2_NOTRACE	0x00000002	/* No ptrace(2) attach or coredumps. */
+#define	P2_NOTRACE_EXEC 0x00000004	/* Keep P2_NOPTRACE on exec(2). */
 
 /* Flags protected by proctree_lock, kept in p_treeflags. */
 #define	P_TREE_ORPHANED		0x00000001	/* Reparented, on orphan list */

Modified: stable/10/sys/sys/procctl.h
==============================================================================
--- stable/10/sys/sys/procctl.h	Sun Jan 25 13:09:53 2015	(r277697)
+++ stable/10/sys/sys/procctl.h	Sun Jan 25 13:15:12 2015	(r277698)
@@ -41,6 +41,8 @@
 #define	PROC_REAP_STATUS	4	/* reaping status */
 #define	PROC_REAP_GETPIDS	5	/* get descendants */
 #define	PROC_REAP_KILL		6	/* kill descendants */
+#define	PROC_TRACE_CTL		7	/* en/dis ptrace and coredumps */
+#define	PROC_TRACE_STATUS	8	/* query tracing status */
 
 /* Operations for PROC_SPROTECT (passed in integer arg). */
 #define	PPROT_OP(x)	((x) & 0xf)
@@ -96,6 +98,10 @@ struct procctl_reaper_kill {
 #define	REAPER_KILL_CHILDREN	0x00000001
 #define	REAPER_KILL_SUBTREE	0x00000002
 
+#define	PROC_TRACE_CTL_ENABLE		1
+#define	PROC_TRACE_CTL_DISABLE		2
+#define	PROC_TRACE_CTL_DISABLE_EXEC	3
+
 #ifndef _KERNEL
 __BEGIN_DECLS
 int	procctl(idtype_t, id_t, int, void *);


More information about the svn-src-all mailing list