@@ -131,6 +131,10 @@ will be used, and CFLAGS sets optimization options for the compiler.
`--enable-lock-elision=yes'
Enable lock elision for pthread mutexes by default.
+`--enable-elision-tune-whitelist=yes'
+ Enable white list for elision environment variable tuning through
+ /etc/glibc-env.cfg.
+
`--enable-pt_chown'
The file `pt_chown' is a helper binary for `grantpt' (*note
Pseudo-Terminals: Allocation.) that is installed setuid root to
@@ -166,6 +166,10 @@
/* Define if lock elision should be enabled by default. */
#undef ENABLE_LOCK_ELISION
+/* Define if environment variable for lock elision tuning should be white listed
+ through /etc/glibc-env.cfg. */
+#undef ENABLE_ELISION_TUNE_WHITELIST
+
/* Package description. */
#undef PKGVERSION
@@ -672,6 +672,7 @@ enable_werror
all_warnings
force_install
bindnow
+enable_elision_tune_whitelist
enable_lock_elision
hardcoded_path_in_tests
use_default_link
@@ -760,6 +761,7 @@ enable_profile
enable_hardcoded_path_in_tests
enable_stackguard_randomization
enable_lock_elision
+enable_elision_tune_whitelist
enable_add_ons
enable_hidden_plt
enable_bind_now
@@ -1416,6 +1418,9 @@ Optional Features:
number at program start
--enable-lock-elision=yes/no
Enable lock elision for pthread mutexes by default
+ --enable-elision-tune-whitelist=yes/no
+ Enable white list for elision environment variable
+ tuning through /etc/glibc-env.cfg
--enable-add-ons[=DIRS...]
configure and build add-ons in DIR1,DIR2,... search
for add-ons if no parameter given
@@ -3488,6 +3493,19 @@ if test "$enable_lock_elision" = yes ; then
fi
+# Check whether --enable-elision-tune-whitelist was given.
+if test "${enable_elision_tune_whitelist+set}" = set; then :
+ enableval=$enable_elision_tune_whitelist; enable_elision_tune_whitelist=$enableval
+else
+ enable_elision_tune_whitelist=no
+fi
+
+
+if test "$enable_elision_tune_whitelist" = yes ; then
+ $as_echo "#define ENABLE_ELISION_TUNE_WHITELIST 1" >>confdefs.h
+
+fi
+
# Check whether --enable-add-ons was given.
if test "${enable_add_ons+set}" = set; then :
enableval=$enable_add_ons;
@@ -177,6 +177,16 @@ if test "$enable_lock_elision" = yes ; then
AC_DEFINE(ENABLE_LOCK_ELISION)
fi
+AC_ARG_ENABLE([elision-tune-whitelist],
+ AC_HELP_STRING([--enable-elision-tune-whitelist[=yes/no]],
+ [Enable white list for elision environment variable tuning through /etc/glibc-env.cfg]),
+ [enable_elision_tune_whitelist=$enableval],
+ [enable_elision_tune_whitelist=no])
+AC_SUBST(enable_elision_tune_whitelist)
+if test "$enable_elision_tune_whitelist" = yes ; then
+ AC_DEFINE(ENABLE_ELISION_TUNE_WHITELIST)
+fi
+
dnl Generic infrastructure for drop-in additions to libc.
AC_ARG_ENABLE([add-ons],
AC_HELP_STRING([--enable-add-ons@<:@=DIRS...@:>@],
@@ -160,6 +160,10 @@ so that they can be invoked directly.
@item --enable-lock-elision=yes
Enable lock elision for pthread mutexes by default.
+@item --enable-elision-tune-whitelist=yes
+Enable white listing for elision environment variable tuning through
+/etc/glibc-env.cfg.
+
@pindex pt_chown
@findex grantpt
@item --enable-pt_chown
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <unistd.h>
#include "config.h"
#define CPUID_FEATURE_RTM (1U << 11)
@@ -111,6 +112,21 @@ elision_override (const char *var, int iter)
{
char *s = getenv(var);
+#ifdef ENABLE_ELISION_TUNE_WHITELIST
+ if (access ("/etc/glibc-env.cfg", R_OK))
+ {
+ if (system("grep 2>/dev/null disallow_elision_tuning /etc/glibc-env.cfg"))
+ {
+ printf ("elision env var override disabled\n");
+ return iter;
+ }
+ if (system("grep 2>/dev/null allow_elision_tuning /etc/glibc-env.cfg"))
+ printf("elision env var override enabled\n");
+ }
+ else
+ return iter;
+#endif
+
s = getenv(var);
if (s && strstr (s, "none"))
return 0;
@@ -22,6 +22,10 @@
#include <elision-conf.h>
#include <unistd.h>
#include <glibc-var.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+
+#define PAIR(x) x, sizeof (x)-1
/* Reasonable initial tuning values, may be revised in the future.
This is a conservative initial value. */
@@ -80,8 +84,6 @@ static const struct tune tunings[] =
{}
};
-#define PAIR(x) x, sizeof (x)-1
-
/* Complain. */
static void
@@ -192,6 +194,125 @@ elision_rwlock_init (const char *s)
complain (PAIR ("pthreads: Unknown setting for GLIBC_PTHREAD_RWLOCK\n"));
}
+#define X86_PAGE_SIZE 4096
+#define ENV_VAR_WHITELIST "/etc/glibc-env.cfg"
+
+/* Does specific M match LINE before END? Write length back to LENP. */
+
+static bool
+match (char *line, char *end, const char *m, int *lenp)
+{
+ int len = strlen (m);
+
+ *lenp = 0;
+ if (len > end - line)
+ return false;
+ if (!strncmp (line, m, len))
+ {
+ *lenp = len;
+ return true;
+ }
+ return false;
+}
+
+/* INTERNAL_SYSCALL does not support 6 argument calls on i386, so do our own
+ mmap stub here. addr and offset are hardcoded to 0 to simplify the
+ assembler. */
+
+static inline void *
+mmap_00(size_t length, int prot, int flags, int fd)
+{
+ void *ret;
+
+#ifdef __i386__
+ asm(
+ "push %%ebx\n\t"
+ "push %%ebp\n\t"
+ "mov %1,%%eax\n\t" /* syscall number */
+ "xor %%ebx,%%ebx\n\t" /* addr */
+ "xor %%ebp,%%ebp\n\t" /* offset */
+ "int $0x80\n\t"
+ "pop %%ebp\n\t"
+ "pop %%ebx\n\t"
+ : "=a" (ret)
+ : "i" (__NR_mmap2), "c" (length), "d" (prot), "S" (flags), "D" (fd));
+#else
+ INTERNAL_SYSCALL_DECL (err);
+ ret = (void *)INTERNAL_SYSCALL (mmap, err, 6, NULL, length,
+ prot, flags, fd, 0);
+#endif
+ return ret;
+}
+
+/* Check extra file to see if we're allowed to use environment variables.
+ Should be moved elsewhere if extended for other purposes. */
+
+static bool
+whitelist_env_var (void)
+{
+ int fd;
+ struct stat st;
+ INTERNAL_SYSCALL_DECL (err);
+ bool ok = false;
+
+#ifndef ENABLE_ELISION_TUNE_WHITELIST
+ return true;
+#endif
+
+ fd = INTERNAL_SYSCALL (open, err, 2, ENV_VAR_WHITELIST, O_RDONLY);
+ if (fd < 0)
+ return false;
+ if (INTERNAL_SYSCALL (fstat, err, 2, fd, &st) >= 0)
+ {
+ size_t size = (st.st_size + X86_PAGE_SIZE - 1) & ~(X86_PAGE_SIZE - 1);
+ char *map = mmap_00 (size, PROT_READ, MAP_SHARED, fd);
+ if (map != (char *)-1L)
+ {
+ char *line;
+ char *end = map + st.st_size;
+
+ for (line = map; line < end; )
+ {
+ while (line < end && (*line == ' ' || *line == '\t' || *line == '\n'))
+ line++;
+ if (line >= end)
+ break;
+ if (*line == '#')
+ {
+ while (line < end && *line != '\n')
+ line++;
+ }
+ else if (*line != '\n')
+ {
+ int len = 0;
+
+ if (match (line, end, "allow_elision_tuning", &len))
+ ok = true;
+ else if (match (line, end, "disallow_elision_tuning", &len))
+ ok = false;
+ else
+ {
+ complain (PAIR ("Unknown configuration specifier in " ENV_VAR_WHITELIST "\n"));
+ len = end - line;
+ if (len > 20)
+ len = 20;
+ complain (line, len);
+ complain (PAIR ("\n"));
+ ok = false;
+ break;
+ }
+ line += len;
+ while (line < end && (*line == ' ' || *line == '\t' || *line == '\n'))
+ line++;
+ }
+ }
+ INTERNAL_SYSCALL (munmap, err, 2, map, size);
+ }
+ }
+ INTERNAL_SYSCALL (close, err, 1, fd);
+ return ok;
+}
+
/* Initialize elison. */
static void
@@ -210,8 +331,11 @@ elision_init (int argc __attribute__ ((unused)),
/* For static builds need to call this explicitely. Noop for dynamic. */
__glibc_var_init (argc, argv, environ);
- elision_mutex_init (_dl_glibc_var[GLIBC_VAR_PTHREAD_MUTEX].val);
- elision_rwlock_init (_dl_glibc_var[GLIBC_VAR_PTHREAD_RWLOCK].val);
+ if (whitelist_env_var ())
+ {
+ elision_mutex_init (_dl_glibc_var[GLIBC_VAR_PTHREAD_MUTEX].val);
+ elision_rwlock_init (_dl_glibc_var[GLIBC_VAR_PTHREAD_RWLOCK].val);
+ }
}
#ifdef SHARED