From 95454b4cadc45eef97fbe244fd75258ee0e179c1 Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Wed, 11 Jan 2023 12:13:10 +0000 Subject: [PATCH] - fix symlink creation under @scope - fix use-after-free on package names --- src/install/install.zig | 66 +++++++++++++++++++++++++++++++--------- src/install/lockfile.zig | 10 ++++-- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/install/install.zig b/src/install/install.zig index 53c9a33b0fad21..c9e19de34bb15a 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1276,30 +1276,66 @@ const PackageInstall = struct { // cache_dir_subpath in here is actually the full path to the symlink pointing to the linked package const symlinked_path = this.cache_dir_subpath; - std.os.symlinkat( - std.fs.path.relative(this.allocator, "node_modules", symlinked_path[0..symlinked_path.len]) catch unreachable, - this.destination_dir.dir.fd, - dest_path[0..dest_path.len], - ) catch |err| { - return Result{ + const subdir = std.fs.path.dirname(dest_path); + var dest_dir = if (subdir) |dir| brk: { + break :brk this.destination_dir.dir.makeOpenPath(dir, .{}) catch |err| return Result{ .fail = .{ .err = err, .step = .linking, }, }; + } else this.destination_dir.dir; + defer { + if (subdir != null) dest_dir.close(); + } + + var dest_full_path = dest_dir.realpathAlloc(this.allocator, ".") catch |err| return Result{ + .fail = .{ + .err = err, + .step = .linking, + }, }; + defer this.allocator.free(dest_full_path); - if (isDanglingSymlink(symlinked_path)) { - return Result{ - .fail = .{ - .err = error.DanglingSymlink, - .step = .linking, - }, - }; - } + var to_path = std.fs.path.resolve(this.allocator, &[_]string{ + FileSystem.instance.top_level_dir, + symlinked_path, + }) catch |err| return Result{ + .fail = .{ + .err = err, + .step = .linking, + }, + }; + defer this.allocator.free(to_path); + + var target = std.fs.path.relative( + this.allocator, + dest_full_path, + to_path, + ) catch |err| return Result{ + .fail = .{ + .err = err, + .step = .linking, + }, + }; + defer this.allocator.free(target); + + std.os.symlinkat(target, dest_dir.fd, std.fs.path.basename(dest_path)) catch |err| return Result{ + .fail = .{ + .err = err, + .step = .linking, + }, + }; + + if (isDanglingSymlink(symlinked_path)) return Result{ + .fail = .{ + .err = error.DanglingSymlink, + .step = .linking, + }, + }; return Result{ - .success = void{}, + .success = {}, }; } diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 5580ab817365c5..bc8ab689a6f6a3 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -2642,10 +2642,14 @@ pub const Package = extern struct { if (json.asProperty(group.prop)) |dependencies_q| { switch (dependencies_q.expr.data) { .e_array => |arr| { + workspace_names = try allocator.alloc(string, arr.items.len); + var workspace_log = logger.Log.init(allocator); defer log.deinit(); - workspace_names = try allocator.alloc(string, arr.items.len); + var workspace_buf = try allocator.alloc(u8, 1024); + defer allocator.free(workspace_buf); + for (arr.slice()) |item, i| { const path = item.asString(allocator) orelse return error.InvalidPackageJSON; @@ -2655,7 +2659,6 @@ pub const Package = extern struct { var workspace_file = try workspace_dir.openFile("package.json", .{ .mode = .read_only }); defer workspace_file.close(); - var workspace_buf = try allocator.alloc(u8, 1024); const workspace_read = try workspace_file.preadAll(workspace_buf, 0); const workspace_source = logger.Source.initPathString(path, workspace_buf[0..workspace_read]); @@ -2667,10 +2670,11 @@ pub const Package = extern struct { if (!workspace_json.has_found_name) return error.InvalidPackageJSON; const workspace_name = workspace_json.found_name; - workspace_names[i] = workspace_name; + string_builder.count(workspace_name); string_builder.count(path); string_builder.cap += bun.MAX_PATH_BYTES; + workspace_names[i] = try allocator.dupe(u8, workspace_name); } total_dependencies_count += @truncate(u32, arr.items.len); },