|
@@ -2660,10 +2660,26 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
|
{
|
|
{
|
|
GB_ASSERT(arg_count <= 7);
|
|
GB_ASSERT(arg_count <= 7);
|
|
|
|
|
|
|
|
+ // FreeBSD additionally clobbers r8, r9, r10, but they
|
|
|
|
+ // can also be used to pass in arguments, so this needs
|
|
|
|
+ // to be handled in two parts.
|
|
|
|
+ bool clobber_arg_regs[7] = {
|
|
|
|
+ false, false, false, false, false, false, false
|
|
|
|
+ };
|
|
|
|
+ if (build_context.metrics.os == TargetOs_freebsd) {
|
|
|
|
+ clobber_arg_regs[4] = true; // r10
|
|
|
|
+ clobber_arg_regs[5] = true; // r8
|
|
|
|
+ clobber_arg_regs[6] = true; // r9
|
|
|
|
+ }
|
|
|
|
+
|
|
char asm_string[] = "syscall";
|
|
char asm_string[] = "syscall";
|
|
gbString constraints = gb_string_make(heap_allocator(), "={rax}");
|
|
gbString constraints = gb_string_make(heap_allocator(), "={rax}");
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
- constraints = gb_string_appendc(constraints, ",{");
|
|
|
|
|
|
+ if (!clobber_arg_regs[i]) {
|
|
|
|
+ constraints = gb_string_appendc(constraints, ",{");
|
|
|
|
+ } else {
|
|
|
|
+ constraints = gb_string_appendc(constraints, ",+{");
|
|
|
|
+ }
|
|
static char const *regs[] = {
|
|
static char const *regs[] = {
|
|
"rax",
|
|
"rax",
|
|
"rdi",
|
|
"rdi",
|
|
@@ -2687,10 +2703,35 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
|
// Some but not all system calls will additionally
|
|
// Some but not all system calls will additionally
|
|
// clobber memory.
|
|
// clobber memory.
|
|
//
|
|
//
|
|
- // TODO: FreeBSD is different and will also clobber
|
|
|
|
- // R8, R9, and R10. Additionally CF is used to
|
|
|
|
- // indicate an error instead of -errno.
|
|
|
|
|
|
+ // As a fix for CVE-2019-5595, FreeBSD started
|
|
|
|
+ // clobbering R8, R9, and R10, instead of restoring
|
|
|
|
+ // them. Additionally unlike Linux, instead of
|
|
|
|
+ // returning negative errno, positive errno is
|
|
|
|
+ // returned and CF is set.
|
|
|
|
+ //
|
|
|
|
+ // TODO:
|
|
|
|
+ // * Figure out what Darwin does.
|
|
|
|
+ // * Add some extra handling to propagate CF back
|
|
|
|
+ // up to the caller on FreeBSD systems so that
|
|
|
|
+ // the caller knows that the return value is
|
|
|
|
+ // positive errno.
|
|
constraints = gb_string_appendc(constraints, ",~{rcx},~{r11},~{memory}");
|
|
constraints = gb_string_appendc(constraints, ",~{rcx},~{r11},~{memory}");
|
|
|
|
+ if (build_context.metrics.os == TargetOs_freebsd) {
|
|
|
|
+ // Second half of dealing with FreeBSD's system
|
|
|
|
+ // call semantics. Explicitly clobber the registers
|
|
|
|
+ // that were not used to pass in arguments, and
|
|
|
|
+ // then clobber RFLAGS.
|
|
|
|
+ if (arg_count < 5) {
|
|
|
|
+ constraints = gb_string_appendc(constraints, ",~{r10}");
|
|
|
|
+ }
|
|
|
|
+ if (arg_count < 6) {
|
|
|
|
+ constraints = gb_string_appendc(constraints, ",~{r8}");
|
|
|
|
+ }
|
|
|
|
+ if (arg_count < 7) {
|
|
|
|
+ constraints = gb_string_appendc(constraints, ",~{r9}");
|
|
|
|
+ }
|
|
|
|
+ constraints = gb_string_appendc(constraints, ",~{cc}");
|
|
|
|
+ }
|
|
|
|
|
|
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
|
|
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
|
|
}
|
|
}
|