CESA-2006-003 - rev 1

[See all my vulnerabilities at http://scary.beasts.org/security]

OpenBSD / NetBSD systrace kernel integer overflow

Programs affected: OpenBSD 3.9, NetBSD 3.
Severity: Local privilege escalation.

systrace is a technology which allows supervision and allow / deny of syscalls made by a supervised process. There is an integer overflow condition in the kernel component of systrace which can be triggered by specifiying large integer values in a systrace ioctl(). The integer overflow condition allows the sidestep of a sanity check, and subsequent out-of-bounds write of a NULL byte to a fairly arbitrary kernel address. Reading of chunks of kernel memory may also be possible.

Possible fruitful attacks here include:

The actual code flaw can be observed in the systrace_preprepl function:

for (i = 0, len = 0; i < repl->strr_nrepl; i++) {
len += repl->strr_offlen[i];
if (repl->strr_offlen[i] == 0)
if (repl->strr_offlen[i] + repl->strr_off[i] > len)
return (EINVAL);

/* Make sure that the length adds up */
if (repl->strr_len != len)
return (EINVAL);

/* Check against a maximum length */
if (repl->strr_len > 2048)
return (EINVAL);

Here, strr_offlen[i] + strr_off[i] can overflow, leading to the attacker's choice of very large strr_offlen or strr_off. The "len" variable is also subject to integer overflow, making the strr_len <= 2048 requirement easy to satisfy. Subsequently, in systrace_replace, the attacker-supplied huge value is used:

if (repl->strr_flags[i] & SYSTR_NOLINKS) {
ret = systrace_fname(strp, kdata, repl->strr_offlen[i]);

And looking at systrace_fname:

systrace_fname(struct str_process *strp, caddr_t kdata, size_t len)
if (strp->nfname >= SYSTR_MAXFNAME || len < 1)
return EINVAL;

strp->fname[strp->nfname] = kdata;
strp->fname[strp->nfname][len - 1] = '\0';

return 0;

"len" is fairly arbitrarily attacker-controlled, leading to the ability to write NULLs anywhere in kernel space. Also, in systrace_replace, there's the use of this attacker-controlled length to copy out to userspace, probably resulting in ability to steal contents of kernel memory:

if (copyout(kdata, udata, repl->strr_offlen[i])) {
ret = EINVAL;
goto out;


CESA-2006-003 - rev 1
Chris Evans