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"); |         throw SysError("getting info about the Nix store mount point"); | ||||||
| 
 | 
 | ||||||
|     if (stat.f_flag & ST_RDONLY) { |     if (stat.f_flag & ST_RDONLY) { | ||||||
|  |         saveMountNamespace(); | ||||||
|  | 
 | ||||||
|         if (unshare(CLONE_NEWNS) == -1) |         if (unshare(CLONE_NEWNS) == -1) | ||||||
|             throw SysError("setting up a private mount namespace"); |             throw SysError("setting up a private mount namespace"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| #include "ssh.hh" | #include "ssh.hh" | ||||||
|  | #include "affinity.hh" | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
|  | @ -34,7 +35,9 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string | ||||||
| 
 | 
 | ||||||
|     auto conn = std::make_unique<Connection>(); |     auto conn = std::make_unique<Connection>(); | ||||||
|     conn->sshPid = startProcess([&]() { |     conn->sshPid = startProcess([&]() { | ||||||
|  |         restoreAffinity(); | ||||||
|         restoreSignals(); |         restoreSignals(); | ||||||
|  |         restoreMountNamespace(); | ||||||
| 
 | 
 | ||||||
|         close(in.writeSide.get()); |         close(in.writeSide.get()); | ||||||
|         close(out.readSide.get()); |         close(out.readSide.get()); | ||||||
|  |  | ||||||
|  | @ -936,6 +936,7 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options) | ||||||
|                 throw SysError("setting death signal"); |                 throw SysError("setting death signal"); | ||||||
| #endif | #endif | ||||||
|             restoreAffinity(); |             restoreAffinity(); | ||||||
|  |             restoreMountNamespace(); | ||||||
|             fun(); |             fun(); | ||||||
|         } catch (std::exception & e) { |         } catch (std::exception & e) { | ||||||
|             try { |             try { | ||||||
|  | @ -1504,4 +1505,26 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> | ||||||
|     return std::unique_ptr<InterruptCallback>(res.release()); |     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; | 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 |             } else | ||||||
|                 env[var.first] = var.second; |                 env[var.first] = var.second; | ||||||
| 
 | 
 | ||||||
|         restoreAffinity(); |  | ||||||
| 
 |  | ||||||
|         /* Run a shell using the derivation's environment.  For
 |         /* Run a shell using the derivation's environment.  For
 | ||||||
|            convenience, source $stdenv/setup to setup additional |            convenience, source $stdenv/setup to setup additional | ||||||
|            environment variables and shell functions.  Also don't |            environment variables and shell functions.  Also don't | ||||||
|  | @ -446,7 +444,9 @@ static void _main(int argc, char * * argv) | ||||||
| 
 | 
 | ||||||
|         auto argPtrs = stringsToCharPtrs(args); |         auto argPtrs = stringsToCharPtrs(args); | ||||||
| 
 | 
 | ||||||
|  |         restoreAffinity(); | ||||||
|         restoreSignals(); |         restoreSignals(); | ||||||
|  |         restoreMountNamespace(); | ||||||
| 
 | 
 | ||||||
|         execvp(shell.c_str(), argPtrs.data()); |         execvp(shell.c_str(), argPtrs.data()); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| #include "eval.hh" | #include "eval.hh" | ||||||
| #include "attr-path.hh" | #include "attr-path.hh" | ||||||
| #include "progress-bar.hh" | #include "progress-bar.hh" | ||||||
|  | #include "affinity.hh" | ||||||
| 
 | 
 | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
|  | @ -72,6 +73,10 @@ struct CmdEdit : InstallableCommand | ||||||
| 
 | 
 | ||||||
|         stopProgressBar(); |         stopProgressBar(); | ||||||
| 
 | 
 | ||||||
|  |         restoreAffinity(); | ||||||
|  |         restoreSignals(); | ||||||
|  |         restoreMountNamespace(); | ||||||
|  | 
 | ||||||
|         execvp(args.front().c_str(), stringsToCharPtrs(args).data()); |         execvp(args.front().c_str(), stringsToCharPtrs(args).data()); | ||||||
| 
 | 
 | ||||||
|         throw SysError("cannot run editor '%s'", editor); |         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 == -1) throw SysError("forking"); | ||||||
|     if (pid == 0) { |     if (pid == 0) { | ||||||
|         restoreAffinity(); |         restoreAffinity(); | ||||||
|  |         restoreSignals(); | ||||||
|  |         restoreMountNamespace(); | ||||||
|         execvp(program.c_str(), stringsToCharPtrs(args2).data()); |         execvp(program.c_str(), stringsToCharPtrs(args2).data()); | ||||||
|         _exit(1); |         _exit(1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -153,9 +153,9 @@ struct CmdRun : InstallablesCommand | ||||||
| 
 | 
 | ||||||
|         stopProgressBar(); |         stopProgressBar(); | ||||||
| 
 | 
 | ||||||
|         restoreSignals(); |  | ||||||
| 
 |  | ||||||
|         restoreAffinity(); |         restoreAffinity(); | ||||||
|  |         restoreSignals(); | ||||||
|  |         restoreMountNamespace(); | ||||||
| 
 | 
 | ||||||
|         /* If this is a diverted store (i.e. its "logical" location
 |         /* If this is a diverted store (i.e. its "logical" location
 | ||||||
|            (typically /nix/store) differs from its "physical" location |            (typically /nix/store) differs from its "physical" location | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue