diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index b4b45d9135..f76985a01a 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -123,15 +123,16 @@ fn findPrefixResolved(cache: *const Cache, resolved_path: []u8) !PrefixedPath { var i: u8 = 1; // Start at 1 to skip over checking the null prefix. while (i < prefixes_slice.len) : (i += 1) { const p = prefixes_slice[i].path.?; - if (p.len > 0 and mem.startsWith(u8, resolved_path, p)) { - // +1 to skip over the path separator here - const sub_path = try gpa.dupe(u8, resolved_path[p.len + 1 ..]); - gpa.free(resolved_path); - return PrefixedPath{ - .prefix = @as(u8, @intCast(i)), - .sub_path = sub_path, - }; - } + var sub_path = getPrefixSubpath(gpa, p, resolved_path) catch |err| switch (err) { + error.NotASubPath => continue, + else => |e| return e, + }; + // Free the resolved path since we're not going to return it + gpa.free(resolved_path); + return PrefixedPath{ + .prefix = i, + .sub_path = sub_path, + }; } return PrefixedPath{ @@ -140,6 +141,22 @@ fn findPrefixResolved(cache: *const Cache, resolved_path: []u8) !PrefixedPath { }; } +fn getPrefixSubpath(allocator: Allocator, prefix: []const u8, path: []u8) ![]u8 { + const relative = try std.fs.path.relative(allocator, prefix, path); + errdefer allocator.free(relative); + var component_iterator = std.fs.path.NativeUtf8ComponentIterator.init(relative) catch { + return error.NotASubPath; + }; + if (component_iterator.root() != null) { + return error.NotASubPath; + } + const first_component = component_iterator.first(); + if (first_component != null and std.mem.eql(u8, first_component.?.name, "..")) { + return error.NotASubPath; + } + return relative; +} + /// This is 128 bits - Even with 2^54 cache entries, the probably of a collision would be under 10^-6 pub const bin_digest_len = 16; pub const hex_digest_len = bin_digest_len * 2; @@ -734,7 +751,7 @@ pub const Manifest = struct { resolved_path: []u8, bytes: []const u8, stat: File.Stat, - ) error{OutOfMemory}!void { + ) !void { assert(self.manifest_file != null); const gpa = self.cache.gpa;