diff options
| author | Marco Trevisan (TreviƱo) <mail@3v1n0.net> | 2025-09-19 06:40:11 +0200 |
|---|---|---|
| committer | Mitchell Hashimoto <m@mitchellh.com> | 2025-09-19 15:54:52 -0700 |
| commit | d55f3e5c4171efcdc0619a961fdbaea3f541c262 (patch) | |
| tree | 7c4417840be6fbc2a91f08c50ecc4dbc822cab75 /src/apprt | |
| parent | 2de105e0353093b8dc966c244c281c77fdb97ce4 (diff) | |
gtk/surface: Filter out the SNAP variables by their contents
When running in a snap context we need to filtering out all the SNAP_*
variables out there, but this is not enough, because it's also needed
to sanitize them by ensuring that no variable containing a path pointing
to a $SNAP folder is leaked there.
Otherwise we might have (for example) XDG_RUNTIME_DIRS containing a
"private" snap path, and that will be exposed to all the applications
that will be started from ghostty
Diffstat (limited to 'src/apprt')
| -rw-r--r-- | src/apprt/gtk/class/surface.zig | 101 |
1 files changed, 89 insertions, 12 deletions
diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig index c26d0c1ef..fb2f2bd47 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -1228,18 +1228,7 @@ pub const Surface = extern struct { // Unset environment varies set by snaps if we're running in a snap. // This allows Ghostty to further launch additional snaps. if (env.get("SNAP")) |_| { - env.remove("SNAP"); - env.remove("DRIRC_CONFIGDIR"); - env.remove("__EGL_EXTERNAL_PLATFORM_CONFIG_DIRS"); - env.remove("__EGL_VENDOR_LIBRARY_DIRS"); - env.remove("LD_LIBRARY_PATH"); - env.remove("LIBGL_DRIVERS_PATH"); - env.remove("LIBVA_DRIVERS_PATH"); - env.remove("VK_LAYER_PATH"); - env.remove("XLOCALEDIR"); - env.remove("GDK_PIXBUF_MODULEDIR"); - env.remove("GDK_PIXBUF_MODULE_FILE"); - env.remove("GTK_PATH"); + try filterSnapPaths(alloc, &env); } // This is a hack because it ties ourselves (optionally) to the @@ -1253,6 +1242,94 @@ pub const Surface = extern struct { return env; } + /// Filter out environment variables that start with forbidden prefixes + fn filterSnapPaths(allocator: std.mem.Allocator, env_map: *std.process.EnvMap) !void { + const snap_paths_vars = [_][]const u8{ + "SNAP", + "SNAP_USER_COMMON", + "SNAP_USER_DATA", + "SNAP_DATA", + "SNAP_COMMON", + }; + + var env_to_remove = std.ArrayList([]const u8).init(allocator); + defer env_to_remove.deinit(); + + var env_to_update = std.ArrayList(struct { + key: []const u8, + value: []const u8, + }).init(allocator); + defer { + for (env_to_update.items) |item| { + allocator.free(item.value); + } + env_to_update.deinit(); + } + + var it = env_map.iterator(); + while (it.next()) |entry| { + const key = entry.key_ptr.*; + const value = entry.value_ptr.*; + + if (std.mem.eql(u8, key, "TERMINFO")) { + continue; + } + + if (std.mem.startsWith(u8, key, "GHOSTTY")) { + continue; + } + + if (std.mem.startsWith(u8, key, "SNAP_")) { + try env_to_remove.append(key); + continue; + } + + var paths = std.mem.splitAny(u8, value, ":"); + var filtered_paths = std.ArrayList([]const u8).init(allocator); + defer filtered_paths.deinit(); + + var modified = false; + while (paths.next()) |path| { + var include = true; + for (snap_paths_vars) |snap_path_var| { + const snap_path_val = env_map.get(snap_path_var); + + if (snap_path_val) |snap_path| { + if (snap_path.len == 0) { + continue; + } + + if (std.mem.startsWith(u8, path, snap_path)) { + include = false; + modified = true; + break; + } + } + } + if (include) { + try filtered_paths.append(path); + } + } + + if (modified) { + if (filtered_paths.items.len > 0) { + const new_value = try std.mem.join(allocator, ":", filtered_paths.items); + try env_to_update.append(.{ .key = key, .value = new_value }); + } else { + try env_to_remove.append(key); + } + } + } + + for (env_to_update.items) |item| { + try env_map.put(item.key, item.value); + } + + for (env_to_remove.items) |key| { + _ = env_map.remove(key); + } + } + pub fn clipboardRequest( self: *Self, clipboard_type: apprt.Clipboard, |
