terminal: fix use-after-free in exec (#8358)

This was only an issue on Linux, as MacOS' command is reallocated and
rewritten. We hit this using embedded Ghostty w/o a login shell :p
pull/8368/head
Mitchell Hashimoto 2025-08-23 12:45:44 -07:00 committed by GitHub
commit 062d596c0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 34 additions and 1 deletions

View File

@ -1513,7 +1513,8 @@ fn execCommand(
}
return switch (command) {
.direct => |v| v,
// We need to clone the command since there's no guarantee the config remains valid.
.direct => |_| (try command.clone(alloc)).direct,
.shell => |v| shell: {
var args: std.ArrayList([:0]const u8) = try .initCapacity(alloc, 4);
@ -1688,3 +1689,35 @@ test "execCommand: direct command, error passwd" {
try testing.expectEqualStrings(result[0], "foo");
try testing.expectEqualStrings(result[1], "bar baz");
}
test "execCommand: direct command, config freed" {
if (comptime builtin.os.tag == .windows) return error.SkipZigTest;
const testing = std.testing;
var arena = ArenaAllocator.init(testing.allocator);
defer arena.deinit();
const alloc = arena.allocator();
var command_arena = ArenaAllocator.init(alloc);
const command_alloc = command_arena.allocator();
const command = try (configpkg.Command{
.direct = &.{
"foo",
"bar baz",
},
}).clone(command_alloc);
const result = try execCommand(alloc, command, struct {
fn get(_: Allocator) !PasswdEntry {
// Failed passwd entry means we can't construct a macOS
// login command and falls back to POSIX behavior.
return error.Fail;
}
});
command_arena.deinit();
try testing.expectEqual(2, result.len);
try testing.expectEqualStrings(result[0], "foo");
try testing.expectEqualStrings(result[1], "bar baz");
}