Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nix
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4331eeb13d24
Choose a base ref
...
head repository: NixOS/nix
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 94dfb6b1fe71
Choose a head ref
  • 10 commits
  • 16 files changed
  • 1 contributor

Commits on Oct 9, 2019

  1. Remove world-writability from per-user directories

    'nix-daemon' now creates subdirectories for users when they first
    connect.
    
    Fixes #509 (CVE-2019-17365).
    Should also fix #3127.
    edolstra committed Oct 9, 2019

    Verified

    This commit was signed with the committer’s verified signature.
    snyk-bot Snyk bot
    Copy the full SHA
    5a30309 View commit details
  2. Copy the full SHA
    c43d9f6 View commit details
  3. nix-profile.sh: Don't create .nix-channels

    This is already done by the installer, so no need to do it again.
    edolstra committed Oct 9, 2019
    Copy the full SHA
    26762ce View commit details
  4. 1
    Copy the full SHA
    9348f92 View commit details
  5. Copy the full SHA
    61a6176 View commit details
  6. Copy the full SHA
    c9159f8 View commit details
  7. Go back to 755 permission on per-user directories

    700 is pointless since the store is world-readable anyway. And
    per-user/root/channels must be world-readable.
    edolstra committed Oct 9, 2019
    Copy the full SHA
    d7bae56 View commit details
  8. Typo

    edolstra committed Oct 9, 2019
    Copy the full SHA
    9277e72 View commit details
  9. Copy the full SHA
    20eec80 View commit details
  10. Merge pull request #3136 from NixOS/no-world-writable

    Remove world-writability from {profiles,gcroots}/per-user
    edolstra authored Oct 9, 2019
    Copy the full SHA
    94dfb6b View commit details
2 changes: 1 addition & 1 deletion nix.spec.in
Original file line number Diff line number Diff line change
@@ -106,7 +106,7 @@ chmod 1775 $RPM_BUILD_ROOT/nix/store
for d in profiles gcroots;
do
mkdir -p $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
chmod 1777 $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
chmod 755 $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
done

# fix permission of nix profile
17 changes: 5 additions & 12 deletions scripts/install-multi-user.sh
Original file line number Diff line number Diff line change
@@ -437,24 +437,17 @@ create_build_users() {
}

create_directories() {
# FIXME: remove all of this because it duplicates LocalStore::LocalStore().

_sudo "to make the basic directory structure of Nix (part 1)" \
mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool}
mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool} /nix/var/nix/{gcroots,profiles}/per-user

_sudo "to make the basic directory structure of Nix (part 2)" \
mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user

_sudo "to make the basic directory structure of Nix (part 3)" \
mkdir -pv -m 1775 /nix/store

_sudo "to make the basic directory structure of Nix (part 4)" \
_sudo "to make the basic directory structure of Nix (part 3)" \
chgrp "$NIX_BUILD_GROUP_NAME" /nix/store

_sudo "to set up the root user's profile (part 1)" \
mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root

_sudo "to set up the root user's profile (part 2)" \
mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr"

_sudo "to place the default nix daemon configuration (part 1)" \
mkdir -pv -m 0555 /etc/nix
}
@@ -497,7 +490,7 @@ EOF
We will:
- make sure your computer doesn't already have Nix files
(if it does, I will tell you how to clean them up.)
(if it does, I will tell you how to clean them up.)
- create local users (see the list above for the users we'll make)
- create a local group ($NIX_BUILD_GROUP_NAME)
- install Nix in to $NIX_ROOT
39 changes: 0 additions & 39 deletions scripts/nix-profile-daemon.sh.in
Original file line number Diff line number Diff line change
@@ -5,45 +5,6 @@ __ETC_PROFILE_NIX_SOURCED=1
export NIX_USER_PROFILE_DIR="@localstatedir@/nix/profiles/per-user/$USER"
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"

# Set up the per-user profile.
mkdir -m 0755 -p $NIX_USER_PROFILE_DIR
if ! test -O "$NIX_USER_PROFILE_DIR"; then
echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2
fi

if test -w $HOME; then
if ! test -L $HOME/.nix-profile; then
if test "$USER" != root; then
ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile
else
# Root installs in the system-wide profile by default.
ln -s @localstatedir@/nix/profiles/default $HOME/.nix-profile
fi
fi

# Subscribe the root user to the NixOS channel by default.
if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels
fi

# Create the per-user garbage collector roots directory.
NIX_USER_GCROOTS_DIR=@localstatedir@/nix/gcroots/per-user/$USER
mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR
if ! test -O "$NIX_USER_GCROOTS_DIR"; then
echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2
fi

# Set up a default Nix expression from which to install stuff.
if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then
rm -f $HOME/.nix-defexpr
mkdir -p $HOME/.nix-defexpr
if [ "$USER" != root ]; then
ln -s @localstatedir@/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root
fi
fi
fi


# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
if [ ! -z "${NIX_SSL_CERT_FILE:-}" ]; then
: # Allow users to override the NIX_SSL_CERT_FILE
48 changes: 2 additions & 46 deletions scripts/nix-profile.sh.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
if [ -n "$HOME" ] && [ -n "$USER" ]; then
__savedpath="$PATH"
export PATH=@coreutils@

# Set up the per-user profile.
# This part should be kept in sync with nixpkgs:nixos/modules/programs/shell.nix
@@ -9,48 +7,6 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then

NIX_USER_PROFILE_DIR=@localstatedir@/nix/profiles/per-user/$USER

mkdir -m 0755 -p "$NIX_USER_PROFILE_DIR"

if [ "$(stat --printf '%u' "$NIX_USER_PROFILE_DIR")" != "$(id -u)" ]; then
echo "Nix: WARNING: bad ownership on "$NIX_USER_PROFILE_DIR", should be $(id -u)" >&2
fi

if [ -w "$HOME" ]; then
if ! [ -L "$NIX_LINK" ]; then
echo "Nix: creating $NIX_LINK" >&2
if [ "$USER" != root ]; then
if ! ln -s "$NIX_USER_PROFILE_DIR"/profile "$NIX_LINK"; then
echo "Nix: WARNING: could not create $NIX_LINK -> $NIX_USER_PROFILE_DIR/profile" >&2
fi
else
# Root installs in the system-wide profile by default.
ln -s @localstatedir@/nix/profiles/default "$NIX_LINK"
fi
fi

# Subscribe the user to the unstable Nixpkgs channel by default.
if [ ! -e "$HOME/.nix-channels" ]; then
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$HOME/.nix-channels"
fi

# Create the per-user garbage collector roots directory.
__user_gcroots=@localstatedir@/nix/gcroots/per-user/"$USER"
mkdir -m 0755 -p "$__user_gcroots"
if [ "$(stat --printf '%u' "$__user_gcroots")" != "$(id -u)" ]; then
echo "Nix: WARNING: bad ownership on $__user_gcroots, should be $(id -u)" >&2
fi
unset __user_gcroots

# Set up a default Nix expression from which to install stuff.
__nix_defexpr="$HOME"/.nix-defexpr
[ -L "$__nix_defexpr" ] && rm -f "$__nix_defexpr"
mkdir -m 0755 -p "$__nix_defexpr"
if [ "$USER" != root ] && [ ! -L "$__nix_defexpr"/channels_root ]; then
ln -s @localstatedir@/nix/profiles/per-user/root/channels "$__nix_defexpr"/channels_root
fi
unset __nix_defexpr
fi

# Append ~/.nix-defexpr/channels to $NIX_PATH so that <nixpkgs>
# paths work when the user has fetched the Nixpkgs channel.
export NIX_PATH=${NIX_PATH:+$NIX_PATH:}$HOME/.nix-defexpr/channels
@@ -78,6 +34,6 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
export MANPATH="$NIX_LINK/share/man:$MANPATH"
fi

export PATH="$NIX_LINK/bin:$__savedpath"
unset __savedpath NIX_LINK NIX_USER_PROFILE_DIR
export PATH="$NIX_LINK/bin:$PATH"
unset NIX_LINK NIX_USER_PROFILE_DIR
fi
29 changes: 23 additions & 6 deletions src/libstore/local-store.cc
Original file line number Diff line number Diff line change
@@ -70,15 +70,17 @@ LocalStore::LocalStore(const Params & params)
createSymlink(profilesDir, gcRootsDir + "/profiles");
}

for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) {
createDirs(perUserDir);
if (chmod(perUserDir.c_str(), 0755) == -1)
throw SysError("could not set permissions on '%s' to 755", perUserDir);
}

createUser(getUserName(), getuid());

/* Optionally, create directories and set permissions for a
multi-user install. */
if (getuid() == 0 && settings.buildUsersGroup != "") {

Path perUserDir = profilesDir + "/per-user";
createDirs(perUserDir);
if (chmod(perUserDir.c_str(), 01777) == -1)
throw SysError(format("could not set permissions on '%1%' to 1777") % perUserDir);

mode_t perm = 01775;

struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
@@ -1432,4 +1434,19 @@ void LocalStore::signPathInfo(ValidPathInfo & info)
}


void LocalStore::createUser(const std::string & userName, uid_t userId)
{
for (auto & dir : {
fmt("%s/profiles/per-user/%s", stateDir, userName),
fmt("%s/gcroots/per-user/%s", stateDir, userName)
}) {
createDirs(dir);
if (chmod(dir.c_str(), 0755) == -1)
throw SysError("changing permissions of directory '%s'", dir);
if (chown(dir.c_str(), userId, 0) == -1)
throw SysError("changing owner of directory '%s'", dir);
}
}


}
2 changes: 2 additions & 0 deletions src/libstore/local-store.hh
Original file line number Diff line number Diff line change
@@ -293,6 +293,8 @@ private:

Path getRealStoreDir() override { return realStoreDir; }

void createUser(const std::string & userName, uid_t userId) override;

friend class DerivationGoal;
friend class SubstitutionGoal;
};
3 changes: 3 additions & 0 deletions src/libstore/store-api.hh
Original file line number Diff line number Diff line change
@@ -628,6 +628,9 @@ public:
return storePath;
}

virtual void createUser(const std::string & userName, uid_t userId)
{ }

protected:

Stats stats;
10 changes: 10 additions & 0 deletions src/libutil/util.cc
Original file line number Diff line number Diff line change
@@ -475,6 +475,16 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix,
}


std::string getUserName()
{
auto pw = getpwuid(geteuid());
std::string name = pw ? pw->pw_name : getEnv("USER", "");
if (name.empty())
throw Error("cannot figure out user name");
return name;
}


static Lazy<Path> getHome2([]() {
Path homeDir = getEnv("HOME");
if (homeDir.empty()) {
2 changes: 2 additions & 0 deletions src/libutil/util.hh
Original file line number Diff line number Diff line change
@@ -126,6 +126,8 @@ void deletePath(const Path & path, unsigned long long & bytesFreed);
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755);

std::string getUserName();

/* Return $HOME or the user's home directory from /etc/passwd. */
Path getHome();

8 changes: 1 addition & 7 deletions src/nix-channel/nix-channel.cc
Original file line number Diff line number Diff line change
@@ -159,13 +159,7 @@ static int _main(int argc, char ** argv)
nixDefExpr = home + "/.nix-defexpr";

// Figure out the name of the channels profile.
;
auto pw = getpwuid(geteuid());
std::string name = pw ? pw->pw_name : getEnv("USER", "");
if (name.empty())
throw Error("cannot figure out user name");
profile = settings.nixStateDir + "/profiles/per-user/" + name + "/channels";
createDirs(dirOf(profile));
profile = fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName());

enum {
cNone,
9 changes: 6 additions & 3 deletions src/nix-daemon/nix-daemon.cc
Original file line number Diff line number Diff line change
@@ -742,7 +742,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
}


static void processConnection(bool trusted)
static void processConnection(bool trusted,
const std::string & userName, uid_t userId)
{
MonitorFdHup monitor(from.fd);

@@ -793,6 +794,8 @@ static void processConnection(bool trusted)
params["path-info-cache-size"] = "0";
auto store = openStore(settings.storeUri, params);

store->createUser(userName, userId);

tunnelLogger->stopWork();
to.flush();

@@ -1053,7 +1056,7 @@ static void daemonLoop(char * * argv)
/* Handle the connection. */
from.fd = remote.get();
to.fd = remote.get();
processConnection(trusted);
processConnection(trusted, user, peer.uid);

exit(0);
}, options);
@@ -1133,7 +1136,7 @@ static int _main(int argc, char * * argv)
}
}
} else {
processConnection(true);
processConnection(true, "root", 0);
}
} else {
daemonLoop(argv);
30 changes: 20 additions & 10 deletions src/nix-env/nix-env.cc
Original file line number Diff line number Diff line change
@@ -192,12 +192,6 @@ static void loadDerivations(EvalState & state, Path nixExprPath,
}


static Path getDefNixExprPath()
{
return getHome() + "/.nix-defexpr";
}


static long getPriority(EvalState & state, DrvInfo & drv)
{
return drv.queryMetaInt("priority", 0);
@@ -1327,9 +1321,20 @@ static int _main(int argc, char * * argv)
Globals globals;

globals.instSource.type = srcUnknown;
globals.instSource.nixExprPath = getDefNixExprPath();
globals.instSource.nixExprPath = getHome() + "/.nix-defexpr";
globals.instSource.systemFilter = "*";

if (!pathExists(globals.instSource.nixExprPath)) {
createDirs(globals.instSource.nixExprPath);
replaceSymlink(
fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName()),
globals.instSource.nixExprPath + "/channels");
if (getuid() != 0)
replaceSymlink(
fmt("%s/profiles/per-user/root/channels", settings.nixStateDir),
globals.instSource.nixExprPath + "/channels_root");
}

globals.dryRun = false;
globals.preserveInstalled = false;
globals.removeAll = false;
@@ -1422,9 +1427,14 @@ static int _main(int argc, char * * argv)

if (globals.profile == "") {
Path profileLink = getHome() + "/.nix-profile";
globals.profile = pathExists(profileLink)
? absPath(readLink(profileLink), dirOf(profileLink))
: canonPath(settings.nixStateDir + "/profiles/default");
if (!pathExists(profileLink)) {
replaceSymlink(
getuid() == 0
? settings.nixStateDir + "/profiles/default"
: fmt("%s/profiles/per-user/%s/profile", settings.nixStateDir, getUserName()),
profileLink);
}
globals.profile = absPath(readLink(profileLink), dirOf(profileLink));
}

op(globals, opFlags, opArgs);
4 changes: 2 additions & 2 deletions tests/nix-channel.sh
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ grep -q 'item.*attrPath="foo".*name="dependencies"' $TEST_ROOT/meta.xml

# Do an install.
nix-env -i dependencies
[ -e $TEST_ROOT/var/nix/profiles/default/foobar ]
[ -e $TEST_HOME/.nix-profile/foobar ]

clearProfiles
rm -f $TEST_HOME/.nix-channels
@@ -55,5 +55,5 @@ grep -q 'item.*attrPath="foo".*name="dependencies"' $TEST_ROOT/meta.xml

# Do an install.
nix-env -i dependencies
[ -e $TEST_ROOT/var/nix/profiles/default/foobar ]
[ -e $TEST_HOME/.nix-profile/foobar ]

5 changes: 0 additions & 5 deletions tests/nix-profile.sh
Original file line number Diff line number Diff line change
@@ -7,8 +7,3 @@ rm -rf $TEST_HOME $TEST_ROOT/profile-var
mkdir -p $TEST_HOME
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh; set"
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh" # test idempotency

[ -L $TEST_HOME/.nix-profile ]
[ -e $TEST_HOME/.nix-channels ]
[ -e $TEST_ROOT/profile-var/nix/gcroots/per-user/$user ]
[ -e $TEST_ROOT/profile-var/nix/profiles/per-user/$user ]
4 changes: 4 additions & 0 deletions tests/remote-store.sh
Original file line number Diff line number Diff line change
@@ -13,3 +13,7 @@ cmp $TEST_ROOT/d1 $TEST_ROOT/d2
nix-store --gc --max-freed 1K

killDaemon

user=$(whoami)
[ -e $NIX_STATE_DIR/gcroots/per-user/$user ]
[ -e $NIX_STATE_DIR/profiles/per-user/$user ]
2 changes: 1 addition & 1 deletion tests/user-envs.sh
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ drvPath10=$(nix-env -f ./user-envs.nix -qa --drv-path --no-name '*' | grep foo-1

# Query descriptions.
nix-env -f ./user-envs.nix -qa '*' --description | grep -q silly
rm -f $HOME/.nix-defexpr
rm -rf $HOME/.nix-defexpr
ln -s $(pwd)/user-envs.nix $HOME/.nix-defexpr
nix-env -qa '*' --description | grep -q silly