aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacques Vidrine <nectar@FreeBSD.org>2005-05-13 00:02:47 +0000
committerJacques Vidrine <nectar@FreeBSD.org>2005-05-13 00:02:47 +0000
commit0c180226e75eaf7f4c7091ff51ac5808e44c9843 (patch)
treed1d70afacc6c84d311e927eeb26cd07af75fb913
parent7b06159f3838a01d1a4b44dc13b7a87df9d0ab98 (diff)
downloadsrc-0c180226e75eaf7f4c7091ff51ac5808e44c9843.tar.gz
src-0c180226e75eaf7f4c7091ff51ac5808e44c9843.zip
Add a knob for disabling/enabling HTT, "machdep.hyperthreading_allowed".
Default off due to information disclosure on multi-user systems. Submitted by: cperciva Reviewed by: jhb Approved by: security-officer
Notes
Notes: svn path=/releng/4.11/; revision=146167
-rw-r--r--UPDATING4
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--sys/i386/i386/mp_machdep.c102
-rw-r--r--sys/i386/include/cpufunc.h8
4 files changed, 115 insertions, 1 deletions
diff --git a/UPDATING b/UPDATING
index 6f4c195a5e6f..3ae1e8dc322c 100644
--- a/UPDATING
+++ b/UPDATING
@@ -17,6 +17,10 @@ minimal number of processes, if possible, for that patch. For those
updates that don't have an advisory, or to be safe, you can do a full
build and install as described in the COMMON ITEMS section.
+20050513: p9 FreeBSD-SA-05:09.htt
+ Add a knob for disabling/enabling HTT. Default off due to information
+ disclosure on multi-user systems.
+
20050508: p8 FreeBSD-SA-05:08.kmem
Correct two issues which were missed from the earlier commit.
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index b8c050ec0d9a..7f7298cac7e4 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -36,7 +36,7 @@
TYPE="FreeBSD"
REVISION="4.11"
-BRANCH="RELEASE-p8"
+BRANCH="RELEASE-p9"
RELEASE="${REVISION}-${BRANCH}"
VERSION="${TYPE} ${RELEASE}"
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index f11b6c02fc07..70589d79784e 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -342,6 +342,9 @@ static int apic_int_is_bus_type(int intr, int bus_type);
static int hlt_cpus_mask;
static int hlt_logical_cpus = 1;
+static u_int hyperthreading_cpus;
+static u_int hyperthreading_cpus_mask;
+static int hyperthreading_allowed;
static struct sysctl_ctx_list logical_cpu_clist;
/*
@@ -982,6 +985,9 @@ mptable_pass2(void)
proc.apic_id++;
(void)processor_entry(&proc, cpu);
logical_cpus_mask |= (1 << cpu);
+ if (hyperthreading_cpus > 1 &&
+ proc.apic_id % hyperthreading_cpus != 0)
+ hyperthreading_cpus_mask |= (1 << cpu);
cpu++;
}
} else if (logical_cpus != 0) {
@@ -993,6 +999,9 @@ mptable_pass2(void)
*/
if (id % logical_cpus != 0)
logical_cpus_mask |= (1 << ID_TO_CPU(id));
+ if (hyperthreading_cpus > 1 &&
+ id % hyperthreading_cpus != 0)
+ hyperthreading_cpus_mask |= (1 << ID_TO_CPU(id));
}
break;
case 1:
@@ -1042,6 +1051,7 @@ static void
mptable_hyperthread_fixup(u_int id_mask)
{
u_int i, id;
+ u_int threads_per_cache, p[4];
/* Nothing to do if there is no HTT support. */
if ((cpu_feature & CPUID_HTT) == 0)
@@ -1051,6 +1061,48 @@ mptable_hyperthread_fixup(u_int id_mask)
return;
/*
+ * Work out if hyperthreading is *really* enabled. This
+ * is made really ugly by the fact that processors lie: Dual
+ * core processors claim to be hyperthreaded even when they're
+ * not, presumably because they want to be treated the same
+ * way as HTT with respect to per-cpu software licensing.
+ * At the time of writing (May 12, 2005) the only hyperthreaded
+ * cpus are from Intel, and Intel's dual-core processors can be
+ * identified via the "deterministic cache parameters" cpuid
+ * calls.
+ */
+ /*
+ * First determine if this is an Intel processor which claims
+ * to have hyperthreading support.
+ */
+ if ((cpu_feature & CPUID_HTT) &&
+ (strcmp(cpu_vendor, "GenuineIntel") == 0)) {
+ /*
+ * If the "deterministic cache parameters" cpuid calls
+ * are available, use them.
+ */
+ if (cpu_high >= 4) {
+ /* Ask the processor about up to 32 caches. */
+ for (i = 0; i < 32; i++) {
+ cpuid_count(4, i, p);
+ threads_per_cache = ((p[0] & 0x3ffc000) >> 14) + 1;
+ if (hyperthreading_cpus < threads_per_cache)
+ hyperthreading_cpus = threads_per_cache;
+ if ((p[0] & 0x1f) == 0)
+ break;
+ }
+ }
+
+ /*
+ * If the deterministic cache parameters are not
+ * available, or if no caches were reported to exist,
+ * just accept what the HTT flag indicated.
+ */
+ if (hyperthreading_cpus == 0)
+ hyperthreading_cpus = logical_cpus;
+ }
+
+ /*
* For each APIC ID of a CPU that is set in the mask,
* scan the other candidate APIC ID's for this
* physical processor. If any of those ID's are
@@ -3044,6 +3096,9 @@ sysctl_htl_cpus(SYSCTL_HANDLER_ARGS)
else
hlt_logical_cpus = 0;
+ if (! hyperthreading_allowed)
+ mask |= hyperthreading_cpus_mask;
+
if ((mask & all_cpus) == all_cpus)
mask &= ~(1<<0);
hlt_cpus_mask = mask;
@@ -3067,6 +3122,9 @@ sysctl_hlt_logical_cpus(SYSCTL_HANDLER_ARGS)
else
hlt_cpus_mask &= ~logical_cpus_mask;
+ if (! hyperthreading_allowed)
+ hlt_cpus_mask |= hyperthreading_cpus_mask;
+
if ((hlt_cpus_mask & all_cpus) == all_cpus)
hlt_cpus_mask &= ~(1<<0);
@@ -3074,6 +3132,34 @@ sysctl_hlt_logical_cpus(SYSCTL_HANDLER_ARGS)
return (error);
}
+static int
+sysctl_hyperthreading_allowed(SYSCTL_HANDLER_ARGS)
+{
+ int allowed, error;
+
+ allowed = hyperthreading_allowed;
+ error = sysctl_handle_int(oidp, &allowed, 0, req);
+ if (error || !req->newptr)
+ return (error);
+
+ if (allowed)
+ hlt_cpus_mask &= ~hyperthreading_cpus_mask;
+ else
+ hlt_cpus_mask |= hyperthreading_cpus_mask;
+
+ if (logical_cpus_mask != 0 &&
+ (hlt_cpus_mask & logical_cpus_mask) == logical_cpus_mask)
+ hlt_logical_cpus = 1;
+ else
+ hlt_logical_cpus = 0;
+
+ if ((hlt_cpus_mask & all_cpus) == all_cpus)
+ hlt_cpus_mask &= ~(1<<0);
+
+ hyperthreading_allowed = allowed;
+ return (error);
+}
+
static void
cpu_hlt_setup(void *dummy __unused)
{
@@ -3093,6 +3179,22 @@ cpu_hlt_setup(void *dummy __unused)
if (hlt_logical_cpus)
hlt_cpus_mask |= logical_cpus_mask;
+
+ /*
+ * If necessary for security purposes, force
+ * hyperthreading off, regardless of the value
+ * of hlt_logical_cpus.
+ */
+ if (hyperthreading_cpus_mask) {
+ TUNABLE_INT_FETCH("machdep.hyperthreading_allowed",
+ &hyperthreading_allowed);
+ SYSCTL_ADD_PROC(&logical_cpu_clist,
+ SYSCTL_STATIC_CHILDREN(_machdep), OID_AUTO,
+ "hyperthreading_allowed", CTLTYPE_INT|CTLFLAG_RW,
+ 0, 0, sysctl_hyperthreading_allowed, "IU", "");
+ if (! hyperthreading_allowed)
+ hlt_cpus_mask |= hyperthreading_cpus_mask;
+ }
}
}
SYSINIT(cpu_hlt, SI_SUB_SMP, SI_ORDER_ANY, cpu_hlt_setup, NULL);
diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h
index 84af22afa5fb..775e74f9e4c0 100644
--- a/sys/i386/include/cpufunc.h
+++ b/sys/i386/include/cpufunc.h
@@ -103,6 +103,14 @@ do_cpuid(u_int ax, u_int *p)
}
static __inline void
+cpuid_count(u_int ax, u_int cx, u_int *p)
+{
+ __asm __volatile("cpuid"
+ : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
+ : "0" (ax), "c" (cx));
+}
+
+static __inline void
enable_intr(void)
{
#ifdef SMP