core: don't try opening config files that are anything but files (#3046)

In a [Discord
thread](https://discord.com/channels/1005603569187160125/1319727495473397791)
someone was having problems running Ghostty because they had
accidentally created a directory called `~/.config/ghostty/config`.
Instead of erroring out Ghostty would hang trying to "read" the
directory. Crashes can also happen if the argument to `--config-file` on
the CLI or a recursively loaded config file.

This patch prevents those hangs or crashes by refusing to read anything
but a plain file (symbolic links to plain files continue to work as
well).
This commit is contained in:
Mitchell Hashimoto
2024-12-22 19:07:53 -08:00
committed by GitHub

View File

@ -2548,9 +2548,21 @@ pub fn loadIter(
pub fn loadFile(self: *Config, alloc: Allocator, path: []const u8) !void {
assert(std.fs.path.isAbsolute(path));
var file = try std.fs.cwd().openFile(path, .{});
var file = try std.fs.openFileAbsolute(path, .{});
defer file.close();
const stat = try file.stat();
switch (stat.kind) {
.file => {},
else => |kind| {
log.warn("config-file {s}: not reading because file type is {s}", .{
path,
@tagName(kind),
});
return;
},
}
std.log.info("reading configuration file path={s}", .{path});
var buf_reader = std.io.bufferedReader(file.reader());
@ -2729,8 +2741,6 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
var loaded = std.StringHashMap(void).init(alloc_gpa);
defer loaded.deinit();
const cwd = std.fs.cwd();
// We need to insert all of our loaded config-file values
// PRIOR to the "-e" in our replay steps, since everything
// after "-e" becomes an "initial-command". To do this, we
@ -2778,7 +2788,7 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
continue;
}
var file = cwd.openFile(path, .{}) catch |err| {
var file = std.fs.openFileAbsolute(path, .{}) catch |err| {
if (err != error.FileNotFound or !optional) {
try self._diagnostics.append(arena_alloc, .{
.message = try std.fmt.allocPrintZ(
@ -2792,6 +2802,21 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
};
defer file.close();
const stat = try file.stat();
switch (stat.kind) {
.file => {},
else => |kind| {
try self._diagnostics.append(arena_alloc, .{
.message = try std.fmt.allocPrintZ(
arena_alloc,
"config-file {s}: not reading because file type is {s}",
.{ path, @tagName(kind) },
),
});
continue;
},
}
log.info("loading config-file path={s}", .{path});
var buf_reader = std.io.bufferedReader(file.reader());
const reader = buf_reader.reader();