Use vfork
This commit is contained in:
		
							parent
							
								
									b5ed5b6e66
								
							
						
					
					
						commit
						0e8fc118b3
					
				
					 3 changed files with 39 additions and 11 deletions
				
			
		|  | @ -863,31 +863,46 @@ void killUser(uid_t uid) | ||||||
| //////////////////////////////////////////////////////////////////////
 | //////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| pid_t startProcess(std::function<void()> fun, | /* Wrapper around vfork to prevent the child process from clobbering
 | ||||||
|     bool dieWithParent, const string & errorPrefix, bool runExitHandlers) |    the caller's stack frame in the parent. */ | ||||||
|  | static pid_t doFork(bool allowVfork, std::function<void()> fun) __attribute__((noinline)); | ||||||
|  | static pid_t doFork(bool allowVfork, std::function<void()> fun) | ||||||
| { | { | ||||||
|  | #ifdef __linux__ | ||||||
|  |     pid_t pid = allowVfork ? vfork() : fork(); | ||||||
|  | #else | ||||||
|     pid_t pid = fork(); |     pid_t pid = fork(); | ||||||
|     if (pid == -1) throw SysError("unable to fork"); | #endif | ||||||
|  |     if (pid != 0) return pid; | ||||||
|  |     fun(); | ||||||
|  |     abort(); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     if (pid == 0) { | 
 | ||||||
|  | pid_t startProcess(std::function<void()> fun, const ProcessOptions & options) | ||||||
|  | { | ||||||
|  |     auto wrapper = [&]() { | ||||||
|         _writeToStderr = 0; |         _writeToStderr = 0; | ||||||
|         try { |         try { | ||||||
| #if __linux__ | #if __linux__ | ||||||
|             if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) |             if (options.dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) | ||||||
|                 throw SysError("setting death signal"); |                 throw SysError("setting death signal"); | ||||||
| #endif | #endif | ||||||
|             restoreAffinity(); |             restoreAffinity(); | ||||||
|             fun(); |             fun(); | ||||||
|         } catch (std::exception & e) { |         } catch (std::exception & e) { | ||||||
|             try { |             try { | ||||||
|                 std::cerr << errorPrefix << e.what() << "\n"; |                 std::cerr << options.errorPrefix << e.what() << "\n"; | ||||||
|             } catch (...) { } |             } catch (...) { } | ||||||
|         } catch (...) { } |         } catch (...) { } | ||||||
|         if (runExitHandlers) |         if (options.runExitHandlers) | ||||||
|             exit(1); |             exit(1); | ||||||
|         else |         else | ||||||
|             _exit(1); |             _exit(1); | ||||||
|     } |     }; | ||||||
|  | 
 | ||||||
|  |     pid_t pid = doFork(options.allowVfork, wrapper); | ||||||
|  |     if (pid == -1) throw SysError("unable to fork"); | ||||||
| 
 | 
 | ||||||
|     return pid; |     return pid; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -269,8 +269,16 @@ void killUser(uid_t uid); | ||||||
| 
 | 
 | ||||||
| /* Fork a process that runs the given function, and return the child
 | /* Fork a process that runs the given function, and return the child
 | ||||||
|    pid to the caller. */ |    pid to the caller. */ | ||||||
| pid_t startProcess(std::function<void()> fun, bool dieWithParent = true, | struct ProcessOptions | ||||||
|     const string & errorPrefix = "error: ", bool runExitHandlers = false); | { | ||||||
|  |     string errorPrefix; | ||||||
|  |     bool dieWithParent; | ||||||
|  |     bool runExitHandlers; | ||||||
|  |     bool allowVfork; | ||||||
|  |     ProcessOptions() : errorPrefix("error: "), dieWithParent(true), runExitHandlers(false), allowVfork(true) { }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = ProcessOptions()); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Run a program and return its stdout in a string (i.e., like the
 | /* Run a program and return its stdout in a string (i.e., like the
 | ||||||
|  |  | ||||||
|  | @ -799,6 +799,11 @@ static void daemonLoop(char * * argv) | ||||||
|                 % (peer.uidKnown ? user : "<unknown>")); |                 % (peer.uidKnown ? user : "<unknown>")); | ||||||
| 
 | 
 | ||||||
|             /* Fork a child to handle the connection. */ |             /* Fork a child to handle the connection. */ | ||||||
|  |             ProcessOptions options; | ||||||
|  |             options.errorPrefix = "unexpected Nix daemon error: "; | ||||||
|  |             options.dieWithParent = false; | ||||||
|  |             options.runExitHandlers = true; | ||||||
|  |             options.allowVfork = false; | ||||||
|             startProcess([&]() { |             startProcess([&]() { | ||||||
|                 fdSocket.close(); |                 fdSocket.close(); | ||||||
| 
 | 
 | ||||||
|  | @ -821,7 +826,7 @@ static void daemonLoop(char * * argv) | ||||||
|                 processConnection(trusted); |                 processConnection(trusted); | ||||||
| 
 | 
 | ||||||
|                 exit(0); |                 exit(0); | ||||||
|             }, false, "unexpected Nix daemon error: ", true); |             }, options); | ||||||
| 
 | 
 | ||||||
|         } catch (Interrupted & e) { |         } catch (Interrupted & e) { | ||||||
|             throw; |             throw; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue