Plug memory disclosures via ptrace(2).

On some architectures, the structures returned by PT_GET*REGS were not
fully populated and could contain uninitialized stack memory.  The same
issue existed with the register files in procfs.

Reported by:	Thomas Barabosch, Fraunhofer FKIE
Reviewed by:	kib
MFC after:	3 days
Security:	kernel stack memory disclosure
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D18421
This commit is contained in:
Mark Johnston 2018-12-03 20:54:17 +00:00
parent 4903c73faf
commit 352aaa5122
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=341442
9 changed files with 36 additions and 9 deletions

View File

@ -2045,6 +2045,7 @@ fill_regs(struct thread *td, struct reg *regs)
int
fill_frame_regs(struct trapframe *tp, struct reg *regs)
{
regs->r_r15 = tp->tf_r15;
regs->r_r14 = tp->tf_r14;
regs->r_r13 = tp->tf_r13;
@ -2076,6 +2077,8 @@ fill_frame_regs(struct trapframe *tp, struct reg *regs)
regs->r_fs = 0;
regs->r_gs = 0;
}
regs->r_err = 0;
regs->r_trapno = 0;
return (0);
}

View File

@ -105,6 +105,8 @@ fill_regs32(struct thread *td, struct reg32 *regs)
regs->r_eflags = tp->tf_rflags;
regs->r_esp = tp->tf_rsp;
regs->r_ss = tp->tf_ss;
regs->r_err = 0;
regs->r_trapno = 0;
return (0);
}

View File

@ -104,6 +104,7 @@ fill_regs(struct thread *td, struct reg *regs)
regs->r_cpsr = tf->tf_spsr;
return (0);
}
int
fill_fpregs(struct thread *td, struct fpreg *regs)
{
@ -134,8 +135,11 @@ set_fpregs(struct thread *td, struct fpreg *regs)
int
fill_dbregs(struct thread *td, struct dbreg *regs)
{
bzero(regs, sizeof(*regs));
return (0);
}
int
set_dbregs(struct thread *td, struct dbreg *regs)
{

View File

@ -112,8 +112,10 @@ procfs_doprocdbregs(PFS_FILL_ARGS)
return (EINVAL);
}
wrap32 = 1;
}
memset(&r32, 0, sizeof(r32));
} else
#endif
memset(&r, 0, sizeof(r));
error = PROC(read, dbregs, td2, &r);
if (error == 0) {
PROC_UNLOCK(p);

View File

@ -102,7 +102,6 @@ procfs_doprocfpregs(PFS_FILL_ARGS)
return (EBUSY);
}
/* XXXKSE: */
td2 = FIRST_THREAD_IN_PROC(p);
#ifdef COMPAT_FREEBSD32
if (SV_CURPROC_FLAG(SV_ILP32)) {
@ -111,8 +110,10 @@ procfs_doprocfpregs(PFS_FILL_ARGS)
return (EINVAL);
}
wrap32 = 1;
}
memset(&r32, 0, sizeof(r32));
} else
#endif
memset(&r, 0, sizeof(r));
error = PROC(read, fpregs, td2, &r);
if (error == 0) {
PROC_UNLOCK(p);

View File

@ -102,7 +102,6 @@ procfs_doprocregs(PFS_FILL_ARGS)
return (EBUSY);
}
/* XXXKSE: */
td2 = FIRST_THREAD_IN_PROC(p);
#ifdef COMPAT_FREEBSD32
if (SV_CURPROC_FLAG(SV_ILP32)) {
@ -111,8 +110,10 @@ procfs_doprocregs(PFS_FILL_ARGS)
return (EINVAL);
}
wrap32 = 1;
}
memset(&r32, 0, sizeof(r32));
} else
#endif
memset(&r, 0, sizeof(r));
error = PROC(read, regs, td2, &r);
if (error == 0) {
PROC_UNLOCK(p);

View File

@ -2816,6 +2816,7 @@ fill_regs(struct thread *td, struct reg *regs)
int
fill_frame_regs(struct trapframe *tp, struct reg *regs)
{
regs->r_fs = tp->tf_fs;
regs->r_es = tp->tf_es;
regs->r_ds = tp->tf_ds;
@ -2831,6 +2832,8 @@ fill_frame_regs(struct trapframe *tp, struct reg *regs)
regs->r_eflags = tp->tf_eflags;
regs->r_esp = tp->tf_esp;
regs->r_ss = tp->tf_ss;
regs->r_err = 0;
regs->r_trapno = 0;
return (0);
}

View File

@ -541,6 +541,9 @@ struct ptrace_args {
* copyin(uap->addr, &r.reg32, sizeof r.reg32);
* .. except this is done at runtime.
*/
#define BZERO(a, s) wrap32 ? \
bzero(a ## 32, s ## 32) : \
bzero(a, s)
#define COPYIN(u, k, s) wrap32 ? \
copyin(u, k ## 32, s ## 32) : \
copyin(u, k, s)
@ -573,7 +576,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
struct ptrace_lwpinfo32 pl32;
struct ptrace_vm_entry32 pve32;
#endif
char args[nitems(td->td_sa.args) * sizeof(register_t)];
char args[sizeof(td->td_sa.args)];
int ptevents;
} r;
void *addr;
@ -590,12 +593,18 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
addr = &r;
switch (uap->req) {
case PT_GET_EVENT_MASK:
case PT_GETREGS:
case PT_GETFPREGS:
case PT_GETDBREGS:
case PT_LWPINFO:
case PT_GET_SC_ARGS:
break;
case PT_GETREGS:
BZERO(&r.reg, sizeof r.reg);
break;
case PT_GETFPREGS:
BZERO(&r.fpreg, sizeof r.fpreg);
break;
case PT_GETDBREGS:
BZERO(&r.dbreg, sizeof r.dbreg);
break;
case PT_SETREGS:
error = COPYIN(uap->addr, &r.reg, sizeof r.reg);
break;
@ -662,6 +671,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
}
#undef COPYIN
#undef COPYOUT
#undef BZERO
#ifdef COMPAT_FREEBSD32
/*

View File

@ -1056,6 +1056,7 @@ fill_fpregs(struct thread *td, struct fpreg *fpregs)
bcopy(pcb->pcb_ufp, fpregs->fr_regs, sizeof(fpregs->fr_regs));
fpregs->fr_fsr = tf->tf_fsr;
fpregs->fr_gsr = tf->tf_gsr;
fpregs->fr_pad[0] = 0;
return (0);
}