| ... | @@ -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, "../") or | 264 | // Packages fetched by URL may not use relative paths to escape outside the |
| 265 | std.mem.eql(u8, pkg_root.sub_path, "..")) and | 265 | // 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); |