<div dir="ltr"><div>From 0bd158632d4479f4d3d27a09f191ed3159e44319 Mon Sep 17 00:00:00 2001</div><div>From: Micah Morton <<a href="mailto:mortonm@chromium.org">mortonm@chromium.org</a>></div><div>Date: Tue, 17 Apr 2018 13:29:03 -0700</div><div>Subject: [PATCH] Allow strongSwan to be spawned as non-root user.</div><div><br></div><div>This patch allows for giving strongSwan only the runtime capabilities it</div><div>needs, rather than full root privileges.</div><div><br></div><div>Adds preprocessor directives which allow strongSwan to be configured to</div><div> 1) start up as a non-root user</div><div> 2) avoid modprobe()'ing IPsec kernel modules into the kernel, which</div><div>    would normally require root or CAP_SYS_MODULE</div><div><br></div><div>Additionally, some small mods to charon/libstrongswan ensure that charon</div><div>supports starting as a non-root user.</div><div><br></div><div>Tested with strongSwan 5.5.3.</div><div>---</div><div> src/charon/charon.c                                        | 13 ++++++++++---</div><div> src/libstrongswan/networking/streams/stream_service_unix.c | 12 ++++++++----</div><div> src/libstrongswan/utils/capabilities.c                     |  5 ++++-</div><div> src/libstrongswan/utils/capabilities.h                     |  4 ++++</div><div> src/starter/starter.c                                      |  7 ++++---</div><div> 5 files changed, 30 insertions(+), 11 deletions(-)</div><div><br></div><div>diff --git a/src/charon/charon.c b/src/charon/charon.c</div><div>index 520cb3c..dffa0a5 100644</div><div>--- a/src/charon/charon.c</div><div>+++ b/src/charon/charon.c</div><div>@@ -224,9 +224,16 @@ static bool check_pidfile()</div><div> <span style="white-space:pre">                   </span>DBG1(DBG_LIB, "setting FD_CLOEXEC for '"PID_FILE"' failed: %s",</div><div> <span style="white-space:pre">                         </span> strerror(errno));</div><div> <span style="white-space:pre">          </span>}</div><div>-<span style="white-space:pre">            </span>ignore_result(fchown(fileno(pidfile),</div><div>-<span style="white-space:pre">                                                        </span> lib->caps->get_uid(lib->caps),</div><div>-<span style="white-space:pre">                                                     </span> lib->caps->get_gid(lib->caps)));</div><div>+<span style="white-space:pre">           </span>/* Only fchown() the pidfile if we have CAP_CHOWN. Otherwise, socket</div><div>+<span style="white-space:pre">         </span> * directory permissions should allow pidfile to be accessed</div><div>+<span style="white-space:pre">         </span> * by the UID/GID under which the charon deamon will run.</div><div>+<span style="white-space:pre">            </span> */</div><div>+<span style="white-space:pre">          </span>if (lib->caps->check(lib->caps, CAP_CHOWN))</div><div>+<span style="white-space:pre">         </span>{</div><div>+<span style="white-space:pre">                    </span>ignore_result(fchown(fileno(pidfile),</div><div>+<span style="white-space:pre">                                                        </span>lib->caps->get_uid(lib->caps),</div><div>+<span style="white-space:pre">                                                      </span>lib->caps->get_gid(lib->caps)));</div><div>+<span style="white-space:pre">            </span>}</div><div> <span style="white-space:pre">           </span>fprintf(pidfile, "%d\n", getpid());</div><div> <span style="white-space:pre">               </span>fflush(pidfile);</div><div> <span style="white-space:pre">    </span>}</div><div>diff --git a/src/libstrongswan/networking/streams/stream_service_unix.c b/src/libstrongswan/networking/streams/stream_service_unix.c</div><div>index 1ed27c4..0e4187d 100644</div><div>--- a/src/libstrongswan/networking/streams/stream_service_unix.c</div><div>+++ b/src/libstrongswan/networking/streams/stream_service_unix.c</div><div>@@ -39,8 +39,9 @@ stream_service_t *stream_service_create_unix(char *uri, int backlog)</div><div> <span style="white-space:pre"> </span>}</div><div> <span style="white-space:pre">   </span>if (!lib->caps->check(lib->caps, CAP_CHOWN))</div><div> <span style="white-space:pre">       </span>{<span style="white-space:pre">    </span>/* required to chown(2) service socket */</div><div>-<span style="white-space:pre">            </span>DBG1(DBG_NET, "socket '%s' requires CAP_CHOWN capability", uri);</div><div>-<span style="white-space:pre">           </span>return NULL;</div><div>+<span style="white-space:pre">         </span>DBG1(DBG_NET, "cannot change ownership of socket '%s' without \</div><div>+<span style="white-space:pre">         </span>CAP_CHOWN capability. socket directory should be accessible to \</div><div>+<span style="white-space:pre">             </span>UID/GID under which deamon will run", uri);</div><div> <span style="white-space:pre">    </span>}</div><div> <span style="white-space:pre">   </span>fd = socket(AF_UNIX, SOCK_STREAM, 0);</div><div> <span style="white-space:pre">       </span>if (fd == -1)</div><div>@@ -58,12 +59,15 @@ stream_service_t *stream_service_create_unix(char *uri, int backlog)</div><div> <span style="white-space:pre">                </span>return NULL;</div><div> <span style="white-space:pre">        </span>}</div><div> <span style="white-space:pre">   </span>umask(old);</div><div>-<span style="white-space:pre">  </span>if (chown(addr.sun_path, lib->caps->get_uid(lib->caps),</div><div>-<span style="white-space:pre">                     </span>  lib->caps->get_gid(lib->caps)) != 0)</div><div>+<span style="white-space:pre">     </span>/* Only attempt to chown() socket if we have CAP_CHOWN */</div><div>+<span style="white-space:pre">    </span>if (lib->caps->check(lib->caps, CAP_CHOWN) &&</div><div>+<span style="white-space:pre">               </span>chown(addr.sun_path, lib->caps->get_uid(lib->caps),</div><div>+<span style="white-space:pre">         </span>lib->caps->get_gid(lib->caps)) != 0)</div><div> <span style="white-space:pre">       </span>{</div><div> <span style="white-space:pre">           </span>DBG1(DBG_NET, "changing socket permissions for '%s' failed: %s",</div><div> <span style="white-space:pre">                  </span> uri, strerror(errno));</div><div> <span style="white-space:pre">     </span>}</div><div>+</div><div> <span style="white-space:pre">   </span>if (listen(fd, backlog) < 0)</div><div> <span style="white-space:pre">     </span>{</div><div> <span style="white-space:pre">           </span>DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));</div><div>diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c</div><div>index ce5f550..bd74e7c 100644</div><div>--- a/src/libstrongswan/utils/capabilities.c</div><div>+++ b/src/libstrongswan/utils/capabilities.c</div><div>@@ -422,7 +422,10 @@ METHOD(capabilities_t, drop, bool,</div><div> {</div><div> #ifndef WIN32</div><div> #ifdef HAVE_PRCTL</div><div>-<span style="white-space:pre">      </span>prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);</div><div>+<span style="white-space:pre">  </span>if (has_capability(this, CAP_SETPCAP, NULL))</div><div>+<span style="white-space:pre"> </span>{</div><div>+<span style="white-space:pre">            </span>prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);</div><div>+<span style="white-space:pre">  </span>}</div><div> #endif</div><div> </div><div> <span style="white-space:pre">   </span>if (this->uid && !init_supplementary_groups(this))</div><div>diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h</div><div>index 20c1855..6b17119 100644</div><div>--- a/src/libstrongswan/utils/capabilities.h</div><div>+++ b/src/libstrongswan/utils/capabilities.h</div><div>@@ -47,6 +47,10 @@ typedef struct capabilities_t capabilities_t;</div><div> #ifndef CAP_DAC_OVERRIDE</div><div> # define CAP_DAC_OVERRIDE 1</div><div> #endif</div><div>+#ifndef CAP_SETPCAP</div><div>+# define CAP_SETPCAP 8</div><div>+#endif</div><div>+</div><div> </div><div> /**</div><div>  * POSIX capability dropping abstraction layer.</div><div>diff --git a/src/starter/starter.c b/src/starter/starter.c</div><div>index 51a42a5..c933de1 100644</div><div>--- a/src/starter/starter.c</div><div>+++ b/src/starter/starter.c</div><div>@@ -477,6 +477,7 @@ int main (int argc, char **argv)</div><div> <span style="white-space:pre">               </span>}</div><div> <span style="white-space:pre">   </span>}</div><div> </div><div>+#ifndef START_AS_NON_ROOT</div><div> <span style="white-space:pre"> </span>/* verify that we can start */</div><div> <span style="white-space:pre">      </span>if (getuid() != 0)</div><div> <span style="white-space:pre">  </span>{</div><div>@@ -484,7 +485,7 @@ int main (int argc, char **argv)</div><div> <span style="white-space:pre">                </span>cleanup();</div><div> <span style="white-space:pre">          </span>exit(LSB_RC_NOT_ALLOWED);</div><div> <span style="white-space:pre">   </span>}</div><div>-</div><div>+#endif</div><div> <span style="white-space:pre">     </span>if (check_pid(pid_file))</div><div> <span style="white-space:pre">    </span>{</div><div> <span style="white-space:pre">           </span>DBG1(DBG_APP, "%s is already running (%s exists) -- skipping daemon start",</div><div>@@ -519,7 +520,7 @@ int main (int argc, char **argv)</div><div> <span style="white-space:pre">            </span>cleanup();</div><div> <span style="white-space:pre">          </span>exit(LSB_RC_INVALID_ARGUMENT);</div><div> <span style="white-space:pre">      </span>}</div><div>-</div><div>+#ifndef SKIP_KERNEL_IPSEC_MODPROBES</div><div> <span style="white-space:pre">        </span>/* determine if we have a native netkey IPsec stack */</div><div> <span style="white-space:pre">      </span>if (!starter_netkey_init())</div><div> <span style="white-space:pre"> </span>{</div><div>@@ -530,7 +531,7 @@ int main (int argc, char **argv)</div><div> <span style="white-space:pre">                        </span>DBG1(DBG_APP, "no known IPsec stack detected, ignoring!");</div><div> <span style="white-space:pre">                </span>}</div><div> <span style="white-space:pre">   </span>}</div><div>-</div><div>+#endif</div><div> <span style="white-space:pre">     </span>last_reload = time_monotonic(NULL);</div><div> </div><div> <span style="white-space:pre">        </span>if (check_pid(starter_pid_file))</div><div>-- </div><div>2.13.5</div></div>