directives. Absolute locations specified in "ca-file", "ca-verify-file" and
"crl-file" prevail and ignore "ca-base".
-chroot <jail dir>
+chroot { <jail dir> | auto }
Changes current directory to <jail dir> and performs a chroot() there before
dropping privileges. This increases the security level in case an unknown
vulnerability would be exploited, since it would make it very hard for the
- attacker to exploit the system. This only works when the process is started
- with superuser privileges. It is important to ensure that <jail_dir> is both
- empty and non-writable to anyone.
+ attacker to exploit the system. It is important to ensure that <jail dir>
+ is both empty and non-writable to anyone. When the process is started with
+ superuser privileges, the chroot() is performed directly. On Linux, when
+ started unprivileged, haproxy attempts to perform it from inside a new
+ user namespace created with unshare(CLONE_NEWUSER); if that mechanism is
+ unavailable the chroot() will fail with the usual error.
+
+ As a special case, <jail dir> may be set to "auto", in which case haproxy
+ creates an anonymous temporary directory, unlinks it, and chroots into it.
+ The resulting jail has no name in the filesystem and is empty and read-only,
+ removing the need to prepare a dedicated jail directory.
close-spread-time <time>
Define a time window during which idle connections and active connections
}
#endif
+static int do_chroot(const char *prog, const char *path)
+{
+ const char *chroot_dir = path;
+ int error = 0;
+
+ if (strcmp(path, "auto") == 0) {
+ /* When "chroot auto" is used, we attempt to chroot to an
+ * anonymous and read-only directory.
+ */
+ char tmpdir[] = "/tmp/haproxy.XXXXXX";
+ chroot_dir = mkdtemp(tmpdir);
+ if (chroot_dir == NULL) {
+ ha_alert("[%s.main()] Cannot create(%s) for chroot auto.\n",
+ prog, tmpdir);
+ return -1;
+ }
+ error = chdir(tmpdir);
+ /* We can call rmdir() here; we hold a reference to the
+ * directory since it is our CWD (and if chdir() failed we still
+ * want to remove the directory).
+ */
+ DISGUISE(rmdir(tmpdir));
+ if (!error)
+ error = chroot(".");
+ } else {
+ error = chroot(path);
+ }
+ if (!error)
+ error = chdir("/");
+
+ if (error) {
+ ha_alert("[%s.main()] Cannot chroot(%s).\n", prog, chroot_dir);
+ return -1;
+ }
+
+ return 0;
+}
+
int main(int argc, char **argv)
{
struct rlimit limit;
/* Must chroot and setgid/setuid in the children */
/* chroot if needed */
- if (global.chroot != NULL) {
- if (chroot(global.chroot) == -1 || chdir("/") == -1) {
- ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
- if (nb_oldpids)
- tell_old_pids(SIGTTIN);
- protocol_unbind_all();
- exit(1);
- }
+ if (global.chroot != NULL && do_chroot(argv[0], global.chroot) != 0) {
+ if (nb_oldpids)
+ tell_old_pids(SIGTTIN);
+ protocol_unbind_all();
+ exit(1);
}
ha_free(&global.chroot);