diff options
Diffstat (limited to 'nix')
| -rw-r--r-- | nix/libstore/build.cc | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc index 20d83fea4a8..4f486f08220 100644 --- a/nix/libstore/build.cc +++ b/nix/libstore/build.cc | |||
| @@ -1621,6 +1621,24 @@ void DerivationGoal::startBuilder() | |||
| 1621 | auto drvName = storePathToName(drvPath); | 1621 | auto drvName = storePathToName(drvPath); |
| 1622 | tmpDir = createTempDir("", "guix-build-" + drvName, false, false, 0700); | 1622 | tmpDir = createTempDir("", "guix-build-" + drvName, false, false, 0700); |
| 1623 | 1623 | ||
| 1624 | if (useChroot) { | ||
| 1625 | /* Make the build directory seen by the build process a sub-directory. | ||
| 1626 | That way, "/tmp/guix-build-foo.drv-0" is root-owned, and thus its | ||
| 1627 | permissions cannot be changed by the build process, while | ||
| 1628 | "/tmp/guix-build-foo.drv-0/top" is owned by the build user. This | ||
| 1629 | cannot be done when !useChroot because then $NIX_BUILD_TOP would | ||
| 1630 | be inaccessible to the build user by its full file name. | ||
| 1631 | |||
| 1632 | If the build user could make the build directory world-writable, | ||
| 1633 | then an attacker could create in it a hardlink to a root-owned file | ||
| 1634 | such as /etc/shadow. If 'keepFailed' is true, the daemon would | ||
| 1635 | then chown that hardlink to the user, giving them write access to | ||
| 1636 | that file. */ | ||
| 1637 | tmpDir += "/top"; | ||
| 1638 | if (mkdir(tmpDir.c_str(), 0700) == 1) | ||
| 1639 | throw SysError("creating top-level build directory"); | ||
| 1640 | } | ||
| 1641 | |||
| 1624 | /* In a sandbox, for determinism, always use the same temporary | 1642 | /* In a sandbox, for determinism, always use the same temporary |
| 1625 | directory. */ | 1643 | directory. */ |
| 1626 | tmpDirInSandbox = useChroot ? canonPath("/tmp", true) + "/guix-build-" + drvName + "-0" : tmpDir; | 1644 | tmpDirInSandbox = useChroot ? canonPath("/tmp", true) + "/guix-build-" + drvName + "-0" : tmpDir; |
| @@ -2626,20 +2644,41 @@ static void _chown(const Path & path, uid_t uid, gid_t gid) | |||
| 2626 | void DerivationGoal::deleteTmpDir(bool force) | 2644 | void DerivationGoal::deleteTmpDir(bool force) |
| 2627 | { | 2645 | { |
| 2628 | if (tmpDir != "") { | 2646 | if (tmpDir != "") { |
| 2647 | // When useChroot is true, tmpDir looks like | ||
| 2648 | // "/tmp/guix-build-foo.drv-0/top". Its parent is root-owned. | ||
| 2649 | string top; | ||
| 2650 | if (useChroot) { | ||
| 2651 | if (baseNameOf(tmpDir) != "top") abort(); | ||
| 2652 | top = dirOf(tmpDir); | ||
| 2653 | } else top = tmpDir; | ||
| 2654 | |||
| 2629 | if (settings.keepFailed && !force) { | 2655 | if (settings.keepFailed && !force) { |
| 2630 | printMsg(lvlError, | 2656 | printMsg(lvlError, |
| 2631 | format("note: keeping build directory `%2%'") | 2657 | format("note: keeping build directory `%2%'") |
| 2632 | % drvPath % tmpDir); | 2658 | % drvPath % top); |
| 2633 | chmod(tmpDir.c_str(), 0755); | 2659 | chmod(tmpDir.c_str(), 0755); |
| 2660 | |||
| 2634 | // Change the ownership if clientUid is set. Never change the | 2661 | // Change the ownership if clientUid is set. Never change the |
| 2635 | // ownership or the group to "root" for security reasons. | 2662 | // ownership or the group to "root" for security reasons. |
| 2636 | if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) { | 2663 | if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) { |
| 2637 | _chown(tmpDir, settings.clientUid, | 2664 | _chown(tmpDir, settings.clientUid, |
| 2638 | settings.clientGid != 0 ? settings.clientGid : -1); | 2665 | settings.clientGid != 0 ? settings.clientGid : -1); |
| 2666 | |||
| 2667 | if (top != tmpDir) { | ||
| 2668 | // Rename tmpDir to its parent, with an intermediate step. | ||
| 2669 | string pivot = top + ".pivot"; | ||
| 2670 | if (rename(top.c_str(), pivot.c_str()) == -1) | ||
| 2671 | throw SysError("pivoting failed build tree"); | ||
| 2672 | if (rename((pivot + "/top").c_str(), top.c_str()) == -1) | ||
| 2673 | throw SysError("renaming failed build tree"); | ||
| 2674 | rmdir(pivot.c_str()); | ||
| 2675 | } | ||
| 2639 | } | 2676 | } |
| 2640 | } | 2677 | } |
| 2641 | else | 2678 | else { |
| 2642 | deletePath(tmpDir); | 2679 | deletePath(tmpDir); |
| 2680 | if (top != tmpDir) rmdir(dirOf(tmpDir).c_str()); | ||
| 2681 | } | ||
| 2643 | tmpDir = ""; | 2682 | tmpDir = ""; |
| 2644 | } | 2683 | } |
| 2645 | } | 2684 | } |
