authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-27 20:50:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-28 04:14:41-05:00
log2a322645331532e22def160677a345854f00b7e2
treeb480cb4010b89a3c0bee1b27d1562b39fe09cb24
parenta98d4a66e957f02e0beb91738ff59e989ad94028

package fetching: catch relative paths that resolve into cache dir

The logic here already caught the case when a dependency path tried to escape out of the zig cache directory using up directories. However, it did not catch the case when the relative path tried to reach into a different path within the zig-cache. For example, if it asked for "../../../blah" then it would be caught, but if it asked for "../blah" then it would try to resolve as "zig-cache/p/blah" and probably result in file-not-found, or perhaps resolve to a different package if someone inadvertently used a valid package hash instead of "blah". Now it correctly gives a "dependency path outside project" error, however, still allows relative paths with up-dirs that were not fetched via URL.

1 files changed, 16 insertions(+), 10 deletions(-)

src/Package/Fetch.zig+16-10
...@@ -261,16 +261,22 @@ pub fn run(f: *Fetch) RunError!void {...@@ -261,16 +261,22 @@ pub fn run(f: *Fetch) RunError!void {
261 f.hash_tok,261 f.hash_tok,
262 try eb.addString("path-based dependencies are not hashed"),262 try eb.addString("path-based dependencies are not hashed"),
263 );263 );
264 if ((std.mem.startsWith(u8, pkg_root.sub_path, "../") or264 // Packages fetched by URL may not use relative paths to escape outside the
265 std.mem.eql(u8, pkg_root.sub_path, "..")) and265 // fetched package directory from within the package cache.
266 pkg_root.root_dir.eql(cache_root))266 if (pkg_root.root_dir.eql(cache_root)) {
267 {267 // `parent_package_root.sub_path` contains a path like this:
268 return f.fail(268 // "p/$hash", or
269 f.location_tok,269 // "p/$hash/foo", with possibly more directories after "foo".
270 try eb.printString("dependency path outside project: '{}{s}'", .{270 // We want to fail unless the resolved relative path has a
271 pkg_root.root_dir, pkg_root.sub_path,271 // prefix of "p/$hash/".
272 }),272 const digest_len = @typeInfo(Manifest.MultiHashHexDigest).Array.len;
273 );273 const expected_prefix = f.parent_package_root.sub_path[0 .. "p/".len + digest_len];
274 if (!std.mem.startsWith(u8, pkg_root.sub_path, expected_prefix)) {
275 return f.fail(
276 f.location_tok,
277 try eb.printString("dependency path outside project: '{}'", .{pkg_root}),
278 );
279 }
274 }280 }
275 f.package_root = pkg_root;281 f.package_root = pkg_root;
276 try loadManifest(f, pkg_root);282 try loadManifest(f, pkg_root);