Disabling ptrace

178 views
Skip to first unread message

Konstantin Belousov

unread,
Dec 30, 2014, 6:19:58 AM12/30/14
to ar...@freebsd.org
The question about a facility to disable introspection functionality
(ptrace etc) for a process was asked several times. The latest query
made me actually code the feature. Note that other systems, e.g. Linux
and OSX, do have similar facilities.

Patch is below, it provides two new procctl(2) requests. PROC_TRACE_ENABLE
enables or disables tracing. It includes core dumping, ptrace, ktrace,
debugging sysctls and hwpmc. PROC_TRACE_STATUS allows to get the tracing
state.

Most interesting question is how should disabling of trace behave
with regard of fork and exec. IMO, the right model is to protect
access to the _program_ address space, which translates to inheritance
of the attribute for fork, and reenabling the tracing on exec. On
the other hand, I understand that some users want to inherit the
tracing disable on exec, so there are PROC_TRACE_SET_DISABLED and
PROC_TRACE_SET_DISABLED_EXEC, the later makes disable to be kept after
exec.

Note that it is trivial for root on the host to circumvent the feature.

diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2
index 649e0ad..4e7e5b8 100644
--- a/lib/libc/sys/procctl.2
+++ b/lib/libc/sys/procctl.2
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 16, 2014
+.Dd December 29, 2014
.Dt PROCCTL 2
.Os
.Sh NAME
@@ -275,6 +275,51 @@ delivery failed, e.g. due to the permission problems.
If no such process exist, the
.Fa rk_fpid
field is set to -1.
+.It Dv PROC_TRACE_ENABLE
+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
+and core dumping.
+Possible values for the
+.Fa data
+argument are:
+.Bl -tag -width "Dv PROC_TRACE_SET_DISABLED_EXEC"
+.It Dv PROC_TRACE_SET_ENABLED
+Enable the tracing, after it was disabled by
+.Dv PROC_TRACE_SET_DISABLED .
+Only allowed for self.
+.It Dv PROC_TRACE_SET_DISABLED
+Disable tracing for the specified process.
+The 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.
+.It Dv PROC_TRACE_SET_DISABLED_EXEC
+Same as
+.Dv PROC_TRACE_SET_DISABLED ,
+but setting persist for the process even after
+.Xr execve 2 .
+.It Dv PROC_TRACE_STATUS
+Returns the current status of tracing for the specified process into
+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, the
+.Fa data
+is set to 0.
+If a debugger is attached,
+.Fa data
+is set to the pid of the debugger process.
.El
.Sh RETURN VALUES
If an error occurs, a value of -1 is returned and
@@ -343,9 +388,28 @@ 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_ENABLE
+request was issued for the process already traced.
+.It Bq Er EPERM
+The
+.Dv PROC_TRACE_ENABLE
+request to re-enable tracing of the process (
+.Dv PROC_TRACE_SET_ENABLED ) ,
+or to disable persistence of the
+.Dv PROC_TRACE_SET_DISABLED
+on
+.Xr execve 2
+was issued for the non-current process.
+.It Bq Er EINVAL
+The value of integer parameter for the
+.Dv PROC_TRACE_ENABLE
+request is invalid.
.El
.Sh SEE ALSO
.Xr kill 2 ,
+.Xr ktrace 2 ,
.Xr ptrace 2 ,
.Xr wait 2 ,
.Xr init 8
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 1457f57..f96e78e 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -2969,6 +2969,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)

switch (uap->com) {
case PROC_SPROTECT:
+ case PROC_TRACE_ENABLE:
error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -2997,6 +2998,9 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
return (error);
data = &x.rk;
break;
+ case PROT_TRACE_STATUS:
+ data = &flags;
+ break;
default:
return (EINVAL);
}
@@ -3012,6 +3016,10 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
if (error == 0)
error = error1;
break;
+ case PROC_TRACE_STATUS:
+ if (error == 0)
+ error = copyout(&flags, uap->data, sizeof(flags));
+ break;
}
return (error);
}
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 19c33b6..5b80f5c 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -634,6 +634,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);
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index f469db6..2c83422 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -494,7 +494,7 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
* 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);
diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
index 9b0d14a..e265ed5 100644
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -280,6 +280,62 @@ reap_kill(struct thread *td, struct proc *p, struct procctl_reaper_kill *rk)
return (error);
}

+static int
+trace_enable(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_SET_ENABLED:
+ if (td->td_proc != p)
+ return (EPERM);
+ p->p_flag2 &= ~(P2_NOTRACE | P2_NOTRACE_EXEC);
+ break;
+ case PROC_TRACE_SET_DISABLED_EXEC:
+ p->p_flag2 |= P2_NOTRACE_EXEC | P2_NOTRACE;
+ break;
+ case PROC_TRACE_SET_DISABLED:
+ 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 procctl_args *uap)

switch (uap->com) {
case PROC_SPROTECT:
+ case PROC_TRACE_ENABLE:
error = copyin(uap->data, &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -328,6 +385,9 @@ sys_procctl(struct thread *td, struct procctl_args *uap)
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 procctl_args *uap)
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, struct proc *p, int com, void *data)
return (reap_getpids(td, p, data));
case PROC_REAP_KILL:
return (reap_kill(td, p, data));
+ case PROC_TRACE_ENABLE:
+ return (trace_enable(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 idtype, id_t id, int com, void *data)
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 idtype, id_t id, int com, void *data)
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 idtype, id_t id, int com, void *data)
case PROC_REAP_STATUS:
case PROC_REAP_GETPIDS:
case PROC_REAP_KILL:
+ case PROC_TRACE_ENABLE:
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 idtype, id_t id, int com, void *data)
error = EINVAL;
break;
}
- sx_unlock(&proctree_lock);
+ if (tree_locked)
+ sx_unlock(&proctree_lock);
return (error);
}
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 2a667b5..a5d9596 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -1714,6 +1714,10 @@ p_candebug(struct thread *td, struct proc *p)
if ((p->p_flag & P_INEXEC) != 0)
return (EBUSY);

+ /* Denied explicitely */
+ if ((p->p_flag2 & P2_NOTRACE) != 0)
+ return (EPERM);
+
return (0);
}

diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index a4f0f88..c4025ba 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -3243,7 +3243,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);
}
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index d7a45e9..4b660d5 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -674,6 +674,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 */
diff --git a/sys/sys/procctl.h b/sys/sys/procctl.h
index d11b2b2..503c09b 100644
--- a/sys/sys/procctl.h
+++ b/sys/sys/procctl.h
@@ -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_ENABLE 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_SET_ENABLED 1
+#define PROC_TRACE_SET_DISABLED 2
+#define PROC_TRACE_SET_DISABLED_EXEC 3
+
#ifndef _KERNEL
__BEGIN_DECLS
int procctl(idtype_t, id_t, int, void *);
_______________________________________________
freebs...@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-arch
To unsubscribe, send any mail to "freebsd-arch...@freebsd.org"

Jilles Tjoelker

unread,
Dec 30, 2014, 9:07:20 AM12/30/14
to Konstantin Belousov, ar...@freebsd.org
On Tue, Dec 30, 2014 at 01:19:41PM +0200, Konstantin Belousov wrote:
> The question about a facility to disable introspection functionality
> (ptrace etc) for a process was asked several times. The latest query
> made me actually code the feature. Note that other systems, e.g. Linux
> and OSX, do have similar facilities.

> Patch is below, it provides two new procctl(2) requests.
> PROC_TRACE_ENABLE enables or disables tracing. It includes core
> dumping, ptrace, ktrace, debugging sysctls and hwpmc.
> PROC_TRACE_STATUS allows to get the tracing state.

> Most interesting question is how should disabling of trace behave
> with regard of fork and exec. IMO, the right model is to protect
> access to the _program_ address space, which translates to inheritance
> of the attribute for fork, and reenabling the tracing on exec.

I agree. I imagine this will be useful for programs like ssh-agent, to
protect their unlocked key material.

This is also what Linux provides, and it is simpler than this patch:
prctl(PR_SET_DUMPABLE) lets a process make their issetugid() equivalent
return true, including preventing tracing by unprivileged users. You
could call that unification a hack.

> On the other hand, I understand that some users want to inherit the
> tracing disable on exec, so there are PROC_TRACE_SET_DISABLED and
> PROC_TRACE_SET_DISABLED_EXEC, the later makes disable to be kept after
> exec.

This is apparently meant to protect a whole process tree as a hardening
measure, or instead of PROC_TRACE_SET_DISABLED if it is undesirable to
modify the program with key material.

> Note that it is trivial for root on the host to circumvent the feature.

I'd prefer if root can still trace normally, without needing any hacks.
Philosophically, FreeBSD should serve the system administrator first and
only then the application programmer. Also, the debugging facilities may
be needed to debug FreeBSD itself (e.g. procstat -k), not just the
application.

--
Jilles Tjoelker

Shawn Webb

unread,
Dec 30, 2014, 10:39:13 AM12/30/14
to freebs...@freebsd.org, Konstantin Belousov, Jilles Tjoelker
It's easy even for non-root to disable or work around ptrace disabling.
LD_PRELOAD, nopping out the instructions, dtrace, etc. Note that for SUID
applications, such tricks don't work. The point is that such protections are
very easily disabled, even by non-root users for non-SUID applications.

I'm curious what the use case was that brought this up. And why the requester
thinks it's actually useful.

We at HardenedBSD have introduced a ptrace hardening patch that limits those
who can use ptrace to a certain group. We've also added hardening around
[lin]procfs. I believe those to be effective against ptrace abuse to a greater
extent. It doesn't, though, handle dtrace, something we still need to
research.

Thanks,

Shawn
signature.asc

Konstantin Belousov

unread,
Dec 30, 2014, 10:58:51 AM12/30/14
to Shawn Webb, Jilles Tjoelker, freebs...@freebsd.org
Google for 'It rather involved being on the other side of this airtight hatchway'.


>
> I'm curious what the use case was that brought this up. And why the requester
> thinks it's actually useful.
>
> We at HardenedBSD have introduced a ptrace hardening patch that limits those
> who can use ptrace to a certain group. We've also added hardening around
> [lin]procfs. I believe those to be effective against ptrace abuse to a greater
> extent. It doesn't, though, handle dtrace, something we still need to
> research.
>
> Thanks,
>
> Shawn


Konstantin Belousov

unread,
Dec 30, 2014, 11:51:47 AM12/30/14
to Jilles Tjoelker, ar...@freebsd.org
On Tue, Dec 30, 2014 at 03:07:10PM +0100, Jilles Tjoelker wrote:
> On Tue, Dec 30, 2014 at 01:19:41PM +0200, Konstantin Belousov wrote:
> > The question about a facility to disable introspection functionality
> > (ptrace etc) for a process was asked several times. The latest query
> > made me actually code the feature. Note that other systems, e.g. Linux
> > and OSX, do have similar facilities.
>
> > Patch is below, it provides two new procctl(2) requests.
> > PROC_TRACE_ENABLE enables or disables tracing. It includes core
> > dumping, ptrace, ktrace, debugging sysctls and hwpmc.
> > PROC_TRACE_STATUS allows to get the tracing state.
>
> > Most interesting question is how should disabling of trace behave
> > with regard of fork and exec. IMO, the right model is to protect
> > access to the _program_ address space, which translates to inheritance
> > of the attribute for fork, and reenabling the tracing on exec.
>
> I agree. I imagine this will be useful for programs like ssh-agent, to
> protect their unlocked key material.
>
> This is also what Linux provides, and it is simpler than this patch:
> prctl(PR_SET_DUMPABLE) lets a process make their issetugid() equivalent
> return true, including preventing tracing by unprivileged users. You
> could call that unification a hack.
Yes, I do not like this. We have nice and proper p_candebug(9) KPI.

>
> > On the other hand, I understand that some users want to inherit the
> > tracing disable on exec, so there are PROC_TRACE_SET_DISABLED and
> > PROC_TRACE_SET_DISABLED_EXEC, the later makes disable to be kept after
> > exec.
>
> This is apparently meant to protect a whole process tree as a hardening
> measure, or instead of PROC_TRACE_SET_DISABLED if it is undesirable to
> modify the program with key material.
Agreed, it could be reinterpreted this way. Do you suggest to change
name for PROC_TRACE_SET_DISABLED_EXEC ? E.g. PROC_TRACE_SET_DISABLED_TREE ?

>
> > Note that it is trivial for root on the host to circumvent the feature.
>
> I'd prefer if root can still trace normally, without needing any hacks.
> Philosophically, FreeBSD should serve the system administrator first and
> only then the application programmer. Also, the debugging facilities may
> be needed to debug FreeBSD itself (e.g. procstat -k), not just the
> application.

This is reasonable. It seems that the only way to enable host root to
use tracing without allowing jail' roots to do the same, is to introduce
new privilege. I changed the p_candebug() chunk to the following:

/* Denied explicitely */
if ((p->p_flag2 & P2_NOTRACE) != 0) {
error = priv_check(td, PRIV_DEBUG_DENIED);
if (error != 0)
return (error);
}

Ed Maste

unread,
Dec 30, 2014, 1:26:30 PM12/30/14
to Shawn Webb, freebs...@freebsd.org
On 30 December 2014 at 10:38, Shawn Webb <lat...@gmail.com> wrote:
>
> I'm curious what the use case was that brought this up. And why the requester
> thinks it's actually useful.

I had one use case for this: LLDB's test suite includes a test for the
debugger handling failure from ptrace(PT_ATTACH, ...), and the test
used the Linux/OS X version of the change under discussion.

As it turns out that case can be easily tested by just having another
ptrace consumer already attached, and the author of the test in LLDB
switched to that approach instead.

Konstantin Belousov

unread,
Dec 30, 2014, 3:44:56 PM12/30/14
to Simon J. Gerraty, freebs...@freebsd.org, Jilles Tjoelker, Shawn Webb
On Tue, Dec 30, 2014 at 12:22:12PM -0800, Simon J. Gerraty wrote:
> Shawn Webb <lat...@gmail.com> wrote:
> > I'm curious what the use case was that brought this up. And why the requester
> > thinks it's actually useful.
>
> Being able to disable ptrace is useful - provided it cannot be bypassed.
> In Junos we leveraged the signed binary implementation (based on NetBSD's
> verified exec) to tag processes for which ptrace should fail. The
> signed binary stuff also supposed to prevent games with LD_PRELOAD -
> assuming we didn't provide and sign the lib in question.
Look. If somebody can preload a library into the process, or arbitrary
modify the text segment, circumventing ptrace(2) ban is a least worry.
The reference to the "Old New Thing" blog I posted before explains
that with with fireworks, based on real 'security reports' sent to the
security team at MS.

>
> When we re-implemented veriexec as a MAC module, the above was left out,
> in anticipation of using a separate module (though perhaps still
> leveraging veriexec to set the labels).

Shawn Webb

unread,
Dec 30, 2014, 3:52:36 PM12/30/14
to Konstantin Belousov, freebs...@freebsd.org, Jilles Tjoelker, Simon J. Gerraty
On Tuesday, December 30, 2014 10:44:45 PM Konstantin Belousov wrote:
> On Tue, Dec 30, 2014 at 12:22:12PM -0800, Simon J. Gerraty wrote:
> > Shawn Webb <lat...@gmail.com> wrote:
> > > I'm curious what the use case was that brought this up. And why the
> > > requester thinks it's actually useful.
> >
> > Being able to disable ptrace is useful - provided it cannot be bypassed.
> > In Junos we leveraged the signed binary implementation (based on NetBSD's
> > verified exec) to tag processes for which ptrace should fail. The
> > signed binary stuff also supposed to prevent games with LD_PRELOAD -
> > assuming we didn't provide and sign the lib in question.
>
> Look. If somebody can preload a library into the process, or arbitrary
> modify the text segment, circumventing ptrace(2) ban is a least worry.
> The reference to the "Old New Thing" blog I posted before explains
> that with with fireworks, based on real 'security reports' sent to the
> security team at MS.

I asked about use case mainly because the applications I'm familiar with that
care about disabling debugging facilities are ones that are trying to deter
reverse engineering. Which is silly.

Disabling ptrace, though, is a great idea overall. I'm all for it. Tools like
libhijack work only through ptrace. Disabling ptrace would also disrupt tools
like libhijack (a good thing).

My only concern was the use case of anti-reverse engineering. Disabling ptrace
in that case is useless.
signature.asc

Simon J. Gerraty

unread,
Dec 30, 2014, 3:57:03 PM12/30/14
to Shawn Webb, Konstantin Belousov, Jilles Tjoelker, freebs...@freebsd.org
Shawn Webb <lat...@gmail.com> wrote:
> I'm curious what the use case was that brought this up. And why the requester
> thinks it's actually useful.

Being able to disable ptrace is useful - provided it cannot be bypassed.
In Junos we leveraged the signed binary implementation (based on NetBSD's
verified exec) to tag processes for which ptrace should fail. The
signed binary stuff also supposed to prevent games with LD_PRELOAD -
assuming we didn't provide and sign the lib in question.

When we re-implemented veriexec as a MAC module, the above was left out,
in anticipation of using a separate module (though perhaps still
leveraging veriexec to set the labels).

Alfred Perlstein

unread,
Dec 30, 2014, 4:46:00 PM12/30/14
to Jilles Tjoelker, Konstantin Belousov, ar...@freebsd.org

On 12/30/14 6:07 AM, Jilles Tjoelker wrote:
> Philosophically, FreeBSD should serve the system administrator first
> and only then the application programmer.
That's a good way to make sure there aren't a lot of FreeBSD systems to
administer. ;)

-Alfred

Simon J. Gerraty

unread,
Dec 30, 2014, 9:47:37 PM12/30/14
to Shawn Webb, Konstantin Belousov, Jilles Tjoelker, freebs...@freebsd.org
Shawn Webb <lat...@gmail.com> wrote:
> I asked about use case mainly because the applications I'm familiar with that
> care about disabling debugging facilities are ones that are trying to deter
> reverse engineering. Which is silly.

Yes, we only do it on the apps responsible for verifying signatures and
the like.

Robert Watson

unread,
Jan 2, 2015, 4:16:55 AM1/2/15
to Konstantin Belousov, ar...@freebsd.org
On Tue, 30 Dec 2014, Konstantin Belousov wrote:

> The question about a facility to disable introspection functionality (ptrace
> etc) for a process was asked several times. The latest query made me
> actually code the feature. Note that other systems, e.g. Linux and OSX, do
> have similar facilities.
>
> Patch is below, it provides two new procctl(2) requests. PROC_TRACE_ENABLE
> enables or disables tracing. It includes core dumping, ptrace, ktrace,
> debugging sysctls and hwpmc. PROC_TRACE_STATUS allows to get the tracing
> state.
>
> Most interesting question is how should disabling of trace behave with
> regard of fork and exec. IMO, the right model is to protect access to the
> _program_ address space, which translates to inheritance of the attribute
> for fork, and reenabling the tracing on exec. On the other hand, I
> understand that some users want to inherit the tracing disable on exec, so
> there are PROC_TRACE_SET_DISABLED and PROC_TRACE_SET_DISABLED_EXEC, the
> later makes disable to be kept after exec.
>
> Note that it is trivial for root on the host to circumvent the feature.

I admit some curiosity about the use case as well -- if this is a security
feature, possibly this should be a property of the credential rather than the
process? Among other things, this could help implement trace limitations in
asynchronous contexts -- not that I'm aware of too many currently, but if
you don't want the I/O of a program traced in the synchronous context, I
guess it might follow that you wouldn't want that to happen asynchronously
either (etc).

On the other hand, if this is a security feature, it doesn't really 'stand
alone' very well, as in absence of a more complete policy, simply disabling
introspection features doesn't provide guarantees, just annoyance until
someone writes a suitable script to work around it. This has been one of my
objections to securelevel, FWIW: while the various bits building it are useful
for admins (e.g., file flages), securelevel isn't a 'coherent' policy that
gives you strong integrity properties, rather, a set of manual frobs and
inconsistent design choices that mean it's very hard to imagine an admin ever
getting it to be useful without running with read-only filesystems, etc (and
even then).

In MAC policies such as Biba and MLS, we mediate the ability to debug target
processes based on additional labels, but there framing integrity and
confidentiality policies give the restriction a security context. In the Mac
OS X version of the MAC Framework, support for disabling debugging following
execve() is slightly more mature in FreeBSD: in FreeBSD it's done based on
label change (a la credential change), but in Mac OS X it tracks a policy
entry point that decides whether the change has access-control significance
(which means you can have information-flow tracking policies that manipulate
labels but don't change functional aspects of the system, which isn't possible
in the FreeBSD version currently). There's a good argument we should pick up
the Mac OS X design choice there at some point.

The reason I wonder about the use case is actually one to do with accurate
performance debugging of systems: ssh, ssh-agent, and friends can already
request that they not be core dumped to avoid leaking keying material to
filesystems, but having them be exempt from hwpmc, DTrace, etc, will make
understanding system and application behaviour harder -- and if they 'fail
silently' then users could suffer potentially confusing (and misleading)
results. Is the general concern here that people are turning on
tracing/profiling/etc tools and not understanding that they may be leaking
keying material?

(Note that we do have a global safety frob to disable ptrace and friends
systemically, security.bsd.unprivileged_proc_debug, which is intended as an
easily available workaround for security vulnerabilities discovered in
process-debugging facilities, which have historically proven a bit
vulnerability-prone across all operating systems I'm aware of. We should
remember this next time we cut an advisory on a ptrace/ktrace/ec
vulnerability.)

Robert

Konstantin Belousov

unread,
Jan 2, 2015, 12:13:26 PM1/2/15
to Robert Watson, ar...@freebsd.org
Use case does not have anything with security. It is obfuscation and
making the introspection harder, for some dynamic scope. AFAIU, it
is the same as the usage of the similar facilities in Linux and OSX.
Everybody involved in conversation understood the inherit limitations
of the reliability of the knob. It is usual cost of implementing vs.
cost of breaking protection scheme. and since exactly this bit of
reverse-engineering defense is asked for many times, I do not see
it much wrong in falling into conformity with other OSes.

I did not intended the PROC_TRACE_ENABLE applied to the programs
manipulating the keying material. I do not see any 'protection'
the ban could add there, user already posses an access to his
own keys. Even if you mean access to the temporal session keys, generated
by for the conversation instance, as opposed to the private key material
used to establish sessions, I do not see why would system need to
actively prevent user from gaining access to it. Inter-credential
barriers must provide adequate separation.

I should note that I very much dislike Ubuntu-style vandalization of
the ptrace(2) API. AFAIK, it only allows PT_ATTACH to the (indirect)
child of the debugger.

WRT putting the trace-disabled indicator into the credentials, instead
of just having it as a process attribute, I am not sure that this is
useful thing. Do you propose to modify existing ucred for the process,
effectively applying the notrace policy to the whole set of processes
sharing the credential, or do COW for ucred on disable ? If not COW,
then the set of the affected processes is somewhat random and too wide.
If COW, I do not see much practical difference with the per-process
bit, esp. due to the execve(2) handling.

Also, I am puzzled by reference to an async context.
Could you provide explicit examples where we do such tracing ?

Robert Watson

unread,
Jan 3, 2015, 8:37:43 AM1/3/15
to Konstantin Belousov, ar...@freebsd.org
On 2 Jan 2015, at 17:13, Konstantin Belousov <kost...@gmail.com> wrote:

> WRT putting the trace-disabled indicator into the credentials, instead
> of just having it as a process attribute, I am not sure that this is
> useful thing. Do you propose to modify existing ucred for the process,
> effectively applying the notrace policy to the whole set of processes
> sharing the credential, or do COW for ucred on disable ? If not COW,
> then the set of the affected processes is somewhat random and too wide.
> If COW, I do not see much practical difference with the per-process
> bit, esp. due to the execve(2) handling.
>
> Also, I am puzzled by reference to an async context.
> Could you provide explicit examples where we do such tracing ?

It’s less about what we do do, and more about what we perhaps should be doing. I had two things vaguely in mind, neither of which is a perfect match:

(1) Normally, we expose the data from synchronous read(), write(), send(), and recv() operations using ktrace — but we don’t currently do this for asynchronous I/O calls. We likely should, in which case I was pondering which of the asynchronously available bits of state we might want to use for it. In principle, we have both the calling process and credential available, so there, the process would be fine.

(2) For other kinds of tracing — specifically, for the audit trail — we make use of saved credentials in a number of cases, and store audit-related filtering data (not so dissimilar from a no-trace flag in some ways) in the credential for this reason. While you are not proposing limiting auditing using this process flag, I think there are a number of structural similarities here that could suggest a similar approach.

In general, we had always planned to allow auditing of far more asynchronous events than we currently do — e.g., firewall events triggered asynchronously by system-call behaviour. We also had loose plans to allow auditing of NFS-originated RPCs, although those are arguably fairly synchronous and not so dissimilar to system calls in various ways.

I’m OK with putting the flag on the process, but frequently the process credential is where we stick security-related subject/object flags...

Robert

Konstantin Belousov

unread,
Jan 3, 2015, 9:25:45 AM1/3/15
to Robert Watson, ar...@freebsd.org
On Sat, Jan 03, 2015 at 01:37:33PM +0000, Robert Watson wrote:
> On 2 Jan 2015, at 17:13, Konstantin Belousov <kost...@gmail.com> wrote:
>
> > WRT putting the trace-disabled indicator into the credentials, instead
> > of just having it as a process attribute, I am not sure that this is
> > useful thing. Do you propose to modify existing ucred for the process,
> > effectively applying the notrace policy to the whole set of processes
> > sharing the credential, or do COW for ucred on disable ? If not COW,
> > then the set of the affected processes is somewhat random and too wide.
> > If COW, I do not see much practical difference with the per-process
> > bit, esp. due to the execve(2) handling.
> >
> > Also, I am puzzled by reference to an async context.
> > Could you provide explicit examples where we do such tracing ?
>
> It???s less about what we do do, and more about what we perhaps should be doing. I had two things vaguely in mind, neither of which is a perfect match:
>
> (1) Normally, we expose the data from synchronous read(), write(), send(), and recv() operations using ktrace ??? but we don???t currently do this for asynchronous I/O calls. We likely should, in which case I was pondering which of the asynchronously available bits of state we might want to use for it. In principle, we have both the calling process and credential available, so there, the process would be fine.
>
> (2) For other kinds of tracing ??? specifically, for the audit trail ??? we make use of saved credentials in a number of cases, and store audit-related filtering data (not so dissimilar from a no-trace flag in some ways) in the credential for this reason. While you are not proposing limiting auditing using this process flag, I think there are a number of structural similarities here that could suggest a similar approach.
>
> In general, we had always planned to allow auditing of far more asynchronous events than we currently do ??? e.g., firewall events triggered asynchronously by system-call behaviour. We also had loose plans to allow auditing of NFS-originated RPCs, although those are arguably fairly synchronous and not so dissimilar to system calls in various ways.

Isn't allowing a process to exempt itself from aduting a real security bug ?

>
> I???m OK with putting the flag on the process, but frequently the process credential is where we stick security-related subject/object flags...

Should I interpret the statement as agreement, in principle, with the patch ?

Konstantin Belousov

unread,
Jan 3, 2015, 11:33:00 AM1/3/15
to Robert Watson, ar...@freebsd.org
On Sat, Jan 03, 2015 at 04:25:35PM +0200, Konstantin Belousov wrote:
> On Sat, Jan 03, 2015 at 01:37:33PM +0000, Robert Watson wrote:
> > I???m OK with putting the flag on the process, but frequently the
> > process credential is where we stick security-related subject/object
> > flags...
Hm, credentials store the rights of the subject, related to the
credentials (am I using the correct terminology ?). While the no-trace
attribute is not rights, it is very similar to e.g. DAC or ACL on the
files, which are stored in inode. No-trace is an attribute of the
process, and by the DAC analogy, should be stored in the object which is
protected.

In other words, we do not disallow some user to do attach with ptrace,
but mark some process as not attachable.

Robert N. M. Watson

unread,
Jan 3, 2015, 12:38:24 PM1/3/15
to Konstantin Belousov, ar...@freebsd.org
On 3 Jan 2015, at 16:32, Konstantin Belousov <kost...@gmail.com> wrote:
>
> On Sat, Jan 03, 2015 at 04:25:35PM +0200, Konstantin Belousov wrote:
>> On Sat, Jan 03, 2015 at 01:37:33PM +0000, Robert Watson wrote:
>>> I???m OK with putting the flag on the process, but frequently the
>>> process credential is where we stick security-related subject/object
>>> flags...
> Hm, credentials store the rights of the subject, related to the
> credentials (am I using the correct terminology ?). While the no-trace
> attribute is not rights, it is very similar to e.g. DAC or ACL on the
> files, which are stored in inode. No-trace is an attribute of the
> process, and by the DAC analogy, should be stored in the object which is
> protected.
>
> In other words, we do not disallow some user to do attach with ptrace,
> but mark some process as not attachable.

Processes are different from most other kernels objects in that they are both subjects and objects of operations. While subject 'credentials' in the classic UNIX model (UIDs, GIDs, additional groups) differ from object metadata (e.g., user/group/permissions), for other models the same data structures are used for both the subject and object (e.g., for most labeled MAC policies). When we do inter-process access control, the credential of the target process is used for most aspects of protection, just as file ownership/permissions would be, so really are its object properties as much as its subject properties.

Robert

Robert Watson

unread,
Jan 3, 2015, 12:51:07 PM1/3/15
to Konstantin Belousov, ar...@freebsd.org
On 3 Jan 2015, at 14:25, Konstantin Belousov <kost...@gmail.com> wrote:
>
>> In general, we had always planned to allow auditing of far more asynchronous events than we currently do ??? e.g., firewall events triggered asynchronously by system-call behaviour. We also had loose plans to allow auditing of NFS-originated RPCs, although those are arguably fairly synchronous and not so dissimilar to system calls in various ways.
>
> Isn't allowing a process to exempt itself from aduting a real security bug ?

Oh, definitely. This was an example, however, of more asynchronous tracing types and events, where having access to the ‘tracing disabled’ state of the originating process might prove important. For example, if we extended ktrace to support tracing some of the same sorts of asynchronous events, where full process context isn’t available, but the events can be cleanly tied back to the initiating process via a saved credential.

>> I???m OK with putting the flag on the process, but frequently the process credential is where we stick security-related subject/object flags...
>
> Should I interpret the statement as agreement, in principle, with the patch ?


As long as it is clearly and carefully documented in the man page that this is a non-security feature, I’m alright with it being brought in. We might want to think about how tools such as DTrace, etc, should report tracing failures when the flag is set.

Robert

Reply all
Reply to author
Forward
0 new messages