Restore parent mount namespace before executing a child process
This ensures that they can't write to /nix/store. Fixes #2535.
This commit is contained in:
		
							parent
							
								
									56f6e382be
								
							
						
					
					
						commit
						a0ef21262f
					
				
					 8 changed files with 48 additions and 4 deletions
				
			
		|  | @ -366,6 +366,8 @@ void LocalStore::makeStoreWritable() | |||
|         throw SysError("getting info about the Nix store mount point"); | ||||
| 
 | ||||
|     if (stat.f_flag & ST_RDONLY) { | ||||
|         saveMountNamespace(); | ||||
| 
 | ||||
|         if (unshare(CLONE_NEWNS) == -1) | ||||
|             throw SysError("setting up a private mount namespace"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include "ssh.hh" | ||||
| #include "affinity.hh" | ||||
| 
 | ||||
| namespace nix { | ||||
| 
 | ||||
|  | @ -34,7 +35,9 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string | |||
| 
 | ||||
|     auto conn = std::make_unique<Connection>(); | ||||
|     conn->sshPid = startProcess([&]() { | ||||
|         restoreAffinity(); | ||||
|         restoreSignals(); | ||||
|         restoreMountNamespace(); | ||||
| 
 | ||||
|         close(in.writeSide.get()); | ||||
|         close(out.readSide.get()); | ||||
|  |  | |||
|  | @ -936,6 +936,7 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options) | |||
|                 throw SysError("setting death signal"); | ||||
| #endif | ||||
|             restoreAffinity(); | ||||
|             restoreMountNamespace(); | ||||
|             fun(); | ||||
|         } catch (std::exception & e) { | ||||
|             try { | ||||
|  | @ -1504,4 +1505,26 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> | |||
|     return std::unique_ptr<InterruptCallback>(res.release()); | ||||
| } | ||||
| 
 | ||||
| static AutoCloseFD fdSavedMountNamespace; | ||||
| 
 | ||||
| void saveMountNamespace() | ||||
| { | ||||
| #if __linux__ | ||||
|     std::once_flag done; | ||||
|     std::call_once(done, []() { | ||||
|         fdSavedMountNamespace = open("/proc/self/ns/mnt", O_RDONLY); | ||||
|         if (!fdSavedMountNamespace) | ||||
|             throw SysError("saving parent mount namespace"); | ||||
|     }); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void restoreMountNamespace() | ||||
| { | ||||
| #if __linux__ | ||||
|     if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1) | ||||
|         throw SysError("restoring parent mount namespace"); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -514,4 +514,13 @@ typedef std::function<bool(const Path & path)> PathFilter; | |||
| extern PathFilter defaultPathFilter; | ||||
| 
 | ||||
| 
 | ||||
| /* Save the current mount namespace. Ignored if called more than
 | ||||
|    once. */ | ||||
| void saveMountNamespace(); | ||||
| 
 | ||||
| /* Restore the mount namespace saved by saveMountNamespace(). Ignored
 | ||||
|    if saveMountNamespace() was never called. */ | ||||
| void restoreMountNamespace(); | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -401,8 +401,6 @@ static void _main(int argc, char * * argv) | |||
|             } else | ||||
|                 env[var.first] = var.second; | ||||
| 
 | ||||
|         restoreAffinity(); | ||||
| 
 | ||||
|         /* Run a shell using the derivation's environment.  For
 | ||||
|            convenience, source $stdenv/setup to setup additional | ||||
|            environment variables and shell functions.  Also don't | ||||
|  | @ -446,7 +444,9 @@ static void _main(int argc, char * * argv) | |||
| 
 | ||||
|         auto argPtrs = stringsToCharPtrs(args); | ||||
| 
 | ||||
|         restoreAffinity(); | ||||
|         restoreSignals(); | ||||
|         restoreMountNamespace(); | ||||
| 
 | ||||
|         execvp(shell.c_str(), argPtrs.data()); | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include "eval.hh" | ||||
| #include "attr-path.hh" | ||||
| #include "progress-bar.hh" | ||||
| #include "affinity.hh" | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| 
 | ||||
|  | @ -72,6 +73,10 @@ struct CmdEdit : InstallableCommand | |||
| 
 | ||||
|         stopProgressBar(); | ||||
| 
 | ||||
|         restoreAffinity(); | ||||
|         restoreSignals(); | ||||
|         restoreMountNamespace(); | ||||
| 
 | ||||
|         execvp(args.front().c_str(), stringsToCharPtrs(args).data()); | ||||
| 
 | ||||
|         throw SysError("cannot run editor '%s'", editor); | ||||
|  |  | |||
|  | @ -285,6 +285,8 @@ static int runProgram(const string & program, const Strings & args) | |||
|     if (pid == -1) throw SysError("forking"); | ||||
|     if (pid == 0) { | ||||
|         restoreAffinity(); | ||||
|         restoreSignals(); | ||||
|         restoreMountNamespace(); | ||||
|         execvp(program.c_str(), stringsToCharPtrs(args2).data()); | ||||
|         _exit(1); | ||||
|     } | ||||
|  |  | |||
|  | @ -153,9 +153,9 @@ struct CmdRun : InstallablesCommand | |||
| 
 | ||||
|         stopProgressBar(); | ||||
| 
 | ||||
|         restoreSignals(); | ||||
| 
 | ||||
|         restoreAffinity(); | ||||
|         restoreSignals(); | ||||
|         restoreMountNamespace(); | ||||
| 
 | ||||
|         /* If this is a diverted store (i.e. its "logical" location
 | ||||
|            (typically /nix/store) differs from its "physical" location | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue