Page MenuHomeFreeBSD

Make randomized stack gap between strings and pointers to argv/envs.
ClosedPublic

Authored by kib on Jul 26 2019, 9:31 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Nov 12, 3:18 PM
Unknown Object (File)
Tue, Nov 12, 5:24 AM
Unknown Object (File)
Tue, Nov 12, 5:02 AM
Unknown Object (File)
Sep 24 2024, 7:28 AM
Unknown Object (File)
Sep 24 2024, 6:45 AM
Unknown Object (File)
Sep 11 2024, 11:38 AM
Unknown Object (File)
Sep 5 2024, 9:57 AM
Unknown Object (File)
Aug 18 2024, 5:11 PM

Details

Summary

This effectively makes the stack base on the csu _start entry randomized.

The gap is enabled if aslr is for the ABI is enabled, and then kern.elf{64,32}.aslr.stack_gap specify the max percentage of the initial stack size that can be wasted for gap. Setting it to zero disables the gap, and max is capped at 50%.

Test Plan

I used the following to print the %rsp/%esp value:

/* $Id: print_sp.c,v 1.2 2019/07/26 21:12:13 kostik Exp kostik $ */

#include <stdio.h>

int
main(void)
{
	unsigned long sp;

#ifdef _LP64
	__asm volatile("movq\t%%rsp,%0" : "=r" (sp));
#else
	__asm volatile("movl\t%%esp,%0" : "=r" (sp));
#endif
	printf("sp %#lx\n", sp);
}

Also I checked that args and environment is correctly passed.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Move the gap above auxv, so that the auxv initialization in static libc sees expected layout.

sys/kern/imgact_elf.c
162 ↗(On Diff #60181)

The description indicates that this is a boolean value, but it is a percentage.

sys/kern/imgact_elf.c
162 ↗(On Diff #60181)

The default value 1 (in this review) also suggests a boolean.

2744 ↗(On Diff #60181)

We should probably bring arc4random_uniform from userland to libkern and use it here, perhaps later.

sys/kern/imgact_elf.c
2742–2743 ↗(On Diff #60181)

When eff_stack_sz is not very large relative to 100, this seems likely to result in more error than first multiplying by the percentage.

Do we anticipate the ULONG_MAX / 50 < eff_stack_sz condition ever?

If not, I think range = eff_stack_sz * pct / 100; makes more sense.

2744 ↗(On Diff #60181)

Totally. I made an attempt before (r346410) but libkern and libc have object name conflicts, so it was reverted. The historical pattern is to copy files into both places :-(.

kib marked 2 inline comments as done.Jul 29 2019, 8:20 PM
kib added inline comments.
sys/kern/imgact_elf.c
162 ↗(On Diff #60181)

Changed to 3 for more amusement.

2742–2743 ↗(On Diff #60181)

Well, in the expression x / y * z, there is no requirements on the order of evaluation imposed by std, since this expression does not have any sequence points. Writing the calculation as two full expressions does impose the order.

In fact I do not think this is very important there, it is up to user to specify a reasonable value for gap pct, and more, the range 1-50 is probably reasonable always.

kib marked an inline comment as done.

Update sysctl description.
Rewrite the formula.

cem added inline comments.
sys/kern/imgact_elf.c
2742–2743 ↗(On Diff #60181)

there is no requirements on the order of evaluation imposed by std

I don't think this is true; the standard defines left-associativity via the syntax.
There is an explicit counter-example in C17/18 §5.1.2.3, 15 "Example 6":

EXAMPLE 6 To illustrate the grouping behavior of expressions, in the following fragment

int a, b;
/* ... */
a = a + 32760 + b + 5;

the expression statement behaves exactly the same as

a = (((a + 32760) + b) + 5);

due to the associativity and precedence of these operators. Thus, the result of the sum (a + 32760) is next added to b , and

that result is then added to 5 which results in the value assigned to a . On a machine in which overflows produce an explicit
trap and in which the range of values representable by an int is [−32768, +32767], the implementation cannot rewrite this
expression as

a = ((a + b) + 32765);

...

and more generally it seems rewriting from left-associative is only allowed if the compiler can know in advance that the computational result is identical.

This revision is now accepted and ready to land.Jul 29 2019, 10:15 PM
sys/kern/imgact_elf.c
163 ↗(On Diff #60250)

Maybe "maximum percentage of main stack to waste on a random gap"?

kib marked an inline comment as done.Jul 31 2019, 7:07 PM
kib added inline comments.
sys/kern/imgact_elf.c
163 ↗(On Diff #60250)

Thanks, I used the wording literally. Will update the review if any further changes are requested.

sys/kern/imgact_elf.c
2747 ↗(On Diff #60250)

Don't we need 16 byte alignment on amd64 at least?

kib marked an inline comment as done.Jul 31 2019, 8:10 PM
kib added inline comments.
sys/kern/imgact_elf.c
2747 ↗(On Diff #60250)

This is not the bottom of the stack, the gap is between strings and the rest (auxv, envp, argv, argc). The final alignment is performed by e.g. sys/amd64/amd64/machdep.c:exec_setregs() which aligns the stack according to the ABI requirements after all the data was copied.