14 Commits 1ba3fb504b ... d249dcc9b0

Author SHA1 Message Date
  Ariadne Devos d249dcc9b0 Test the character class of tokens 5 years ago
  Ariadne Devos 83c2666393 Merge branch 'odd-fixes' into webdav 5 years ago
  Ariadne Devos 44e36f901d Test the actual bit test implementation 5 years ago
  Ariadne Devos db452a4eb7 Remove buggy, tricky x86 special case 5 years ago
  Ariadne Devos 801480cb71 Dereference pointer 5 years ago
  Ariadne Devos 9115368b6e Allow efficient bitvectors 5 years ago
  Ariadne Devos f5b714e4a6 Fix syntax and type errors 5 years ago
  Ariadne Devos f813c9fbdd Fix broken assembly syntax 5 years ago
  Ariadne Devos 72bf4f7a5f Collaterally evolve to hidden comparison operators 5 years ago
  Ariadne Devos ce4dfa318b Introduce hidden comparison operators 5 years ago
  Ariadne Devos dc9f3a965a Introduce terse hidden comparison operators 5 years ago
  Ariadne Devos a953b245e3 Add missing taskset.h header 5 years ago
  Ariadne Devos 479553c085 Define macro for testing constantness 5 years ago
  Ariadne Devos 3a6d9bb393 Allow tainting memory 5 years ago
10 changed files with 254 additions and 38 deletions
  1. 124 0
      collateral/test-hidden.smpl
  2. 22 21
      collateral/spectre.spatch
  3. 6 5
      fd/fd.c
  4. 6 5
      fd/inet.c
  5. 4 3
      http/accept.c
  6. 37 0
      http/lex.c
  7. 5 4
      http/stream.c
  8. 46 0
      sHT/bitvec.h
  9. 4 0
      sHT/compiler.h
  10. 0 0
      sHT/scheduling.h

+ 124 - 0
collateral/test-hidden.smpl

@@ -0,0 +1,124 @@
+// s2 -- replace many sHT_test_hidden
+// Copyright (C) 2018 Ariadne Devos
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+@ test_self @
+expression e;
+@@
+- sHT_test_hidden(e, e)
++ sHT_nonzero_p(e)
+
+@ test_nonzero @
+expression e;
+@@
+- sHT_test_hidden(e, e != 0)
++ sHT_nonzero_p(e)
+
+@ test_zero @
+expression e;
+@@
+- sHT_test_hidden(e, e == 0)
++ sHT_zero_p(e)
+
+@ test_null @
+expression e;
+@@
+- sHT_test_hidden(e, e == NULL)
++ sHT_null_p(e)
+
+@ test_lt0 @
+int e;
+@@
+- sHT_test_hidden(e, e < 0)
++ sHT_lt0(e)
+
+@ test_ge0 @
+expression e;
+@@
+- sHT_test_hidden(e, e >= 0)
++ !sHT_lt0(e)
+
+@ test_ge1 @
+expression e, f;
+@@
+- sHT_test_hidden(e, e >= f)
++ sHT_ge(e, f)
+
+@ test_ge2 @
+expression e, f;
+@@
+- sHT_test_hidden2(e, f, e >= f)
++ sHT_ge(e, f)
+
+@ test_gt1 @
+expression e, f;
+@@
+- sHT_test_hidden(e, e > f)
++ sHT_gt(e, f)
+
+@ test_gt2 @
+expression e, f;
+@@
+- sHT_test_hidden2(e, f, e > f)
++ sHT_gt(e, f)
+
+@ test_lt1 @
+expression e, f != 0;
+@@
+- sHT_test_hidden(\(e\|f\), e < f)
++ sHT_gt(f, e)
+
+@ test_lt2 @
+expression e, f;
+@@
+- sHT_test_hidden2(e, f, e < f)
++ sHT_gt(f, e)
+
+@ test_and1_not @
+expression e, f;
+@@
+- sHT_test_hidden(e, !(e & f))
++ !sHT_and_any(e, f)
+
+@ test_and2_not @
+expression e, f;
+@@
+- sHT_test_hidden2(e, ..., !(e & f))
++ !sHT_and_any(e, f)
+
+@ test_and1 @
+expression e, f;
+@@
+- sHT_test_hidden(e, e & f)
++ sHT_and_any(e, f)
+
+@ test_and2 @
+expression e, f;
+@@
+- sHT_test_hidden2(e, ..., e & f)
++ sHT_and_any(e, f)
+
+@ has_tests @
+@@
+ \(sHT_gt\|sHT_ge\|sHT_lt0\|sHT_null_p\|sHT_zero_p\|sHT_nonzero_p\|sHT_and_any\)
+
+@ test_header @
+@@
+  #include <sHT/test.h>
+
+@ introduce_test_header depends on has_tests && !test_header @
+@@
+  #include <sHT/compiler.h>
++ #include <sHT/test.h>

+ 22 - 21
collateral/spectre.spatch

@@ -1,4 +1,4 @@
-// s2 - apply Spectre mitigations
+// s2 -- replace some superfluous likely/unlikely
 // Copyright (C) 2018 Ariadne Devos
 //
 // This program is free software: you can redistribute it and/or modify
@@ -12,27 +12,28 @@
 // GNU General Public License for more details.
 //
 // You should have received a copy of the GNU General Public License
-// along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-@ h1_compare @ 
-expression dep;
-local idexpression a, b;
-binary operator op;
+@ double_unlikely @
 @@
-// e.g, i < n
-- sHT_test_hidden(dep, a op b)
-+ sHT_test_hidden2(a, b, a op b)
+- sHT_unlikely(
+  \(sHT_gt\|sHT_ge\|sHT_eq\|sHT_lt0\|sHT_zero_p\|sHT_nonzero_p\|sHT_eq_pointer\|sHT_null_p\)(...)
+- )
 
-@ h1_array_loop @
-statement T;
-identifier i;
-idexpression n;
-binary operator op;
+@ double_likely @
 @@
-  for (
-  ...;
-- i op n
-+ sHT_test_hidden2(i, n, i op n)
-  ;
-  i++)
-  T
+- sHT_likely(
+  !\(sHT_gt\|sHT_ge\|sHT_eq\|sHT_lt0\|sHT_zero_p\|sHT_nonzero_p\|sHT_eq_pointer\|sHT_null_p\)(...)
+- )
+
+@ correct_likely_zero @
+expression e;
+@@
+- sHT_likely(sHT_zero_p(e))
++ !sHT_nonzero_p(e)
+
+@ correct_likely_nonzero @
+expression e;
+@@
+- sHT_likely(sHT_nonzero_p(e))
++ !sHT_zero_p(e)

+ 6 - 5
fd/fd.c

@@ -15,8 +15,9 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include "fd.h"
-#include <sHT/compiler.h>
 #include <sHT/bugs.h>
+#include <sHT/compiler.h>
+#include <sHT/test.h>
 
 #include <errno.h>
 #include <unistd.h>
@@ -32,10 +33,10 @@ sHT_close(int fd)
 	   don't know about NetBSD,
 	   I presume the Hurd. */
 	int ret = close(fd);
-	if (sHT_likely(sHT_test_hidden(ret, ret == 0)))
+	if (!sHT_nonzero_p(ret))
 		return;
 	int err = errno;
-	if (sHT_likely(sHT_test_hidden(err, err != EBADFD)))
-		return;
-	sHT_bug(&sHT_close_bug, err);
+	if (sHT_eq(err, EBADFD))
+		sHT_bug(&sHT_close_bug, err);
+	return;
 }

+ 6 - 5
fd/inet.c

@@ -17,6 +17,7 @@
 #include "fd.h"
 
 #include <sHT/compiler.h>
+#include <sHT/test.h>
 
 #include <errno.h>
 #include <netinet/in.h>
@@ -34,20 +35,20 @@ int
 sHT_passive_ipv6(const struct sHT_passive_in6 *in)
 {
 	int fd = socket(AF_INET6, in->type, 0);
-	if (sHT_unlikely(sHT_test_hidden(fd, fd < 0)))
+	if (sHT_lt0(fd))
 		return -errno;
 	int ret = sHT_enable_sockopt(fd, IPPROTO_IP, IP_FREEBIND);
-	if (sHT_unlikely(sHT_test_hidden(ret, ret)))
+	if (sHT_nonzero_p(ret))
 		goto socket;
 	ret = sHT_enable_sockopt(fd, SOL_SOCKET, SO_REUSEPORT);
-	if (sHT_unlikely(sHT_test_hidden(ret, ret)))
+	if (sHT_nonzero_p(ret))
 		goto socket;
 	/* XXX SO_ATTACH_BPF (seccomp filtering) */
 	ret = bind(fd, (struct sockaddr *) &in->addr, sizeof(in->addr));
-	if (sHT_unlikely(sHT_test_hidden(ret, ret < 0)))
+	if (sHT_lt0(ret))
 		goto socket;
 	ret = listen(fd, in->backlog);
-	if (sHT_unlikely(sHT_test_hidden(ret, ret < 0)))
+	if (sHT_lt0(ret))
 		goto socket;
 	return fd;
 

+ 4 - 3
http/accept.c

@@ -17,12 +17,13 @@
 #include "worker.h"
 #include "fd.h"
 
+#include <sHT/accept.h>
 #include <sHT/bugs.h>
 #include <sHT/compiler.h>
 #include <sHT/nospec.h>
 #include <sHT/resource.h>
 #include <sHT/stream.h>
-#include <sHT/accept.h>
+#include <sHT/test.h>
 
 #include <string.h>
 
@@ -53,7 +54,7 @@ void
 sHT_accept_logic(struct sHT_worker *worker, struct sHT_task_accept *task, struct sHT_task_stream *subtask)
 {
 	_Bool oops = sHT_init_stream(worker->papers, &subtask->stream);
-	if (sHT_unlikely(sHT_test_hidden(oops, oops))) {
+	if (sHT_nonzero_p(oops)) {
 		/* XXX Spectre: what if this branch is ignored?
 		   Then a NULL paper might be written to,
 		   might be problematic.  */
@@ -64,7 +65,7 @@ sHT_accept_logic(struct sHT_worker *worker, struct sHT_task_accept *task, struct
 	/* TODO: consider patching the kernel to allow 'reservation' of
 	   epoll events. TODO: reconsider this previous TODO. */
 	oops = sHT_install_edge_trigger(worker->watches, subtask->stream.fd, &subtask->task);
-	if (sHT_unlikely(sHT_test_hidden(oops, oops))) {
+	if (sHT_nonzero_p(oops)) {
 		/* Spectre: a speculatively missing watch isn't problematic.
 		   For a teeny while,
 		   the task won't run although it should be. */

+ 37 - 0
http/lex.c

@@ -0,0 +1,37 @@
+/* s2 - for lexing HTTP requests
+   Copyright (C) 2018 Ariadne Devos
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <sHT/web/lex1.h>
+
+const uint8_t s2_http_token[32] = {
+	0, 0, 0, 0,
+	0b11111010,
+	0b01101100,
+	0b11111111,
+	0b00000011,
+	0b11111110,
+	0b11111111,
+	0b11111111,
+	0b11000111,
+	0b11111111,
+	0b11111111,
+	0b11111111,
+	0b01010111,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+};

+ 5 - 4
http/stream.c

@@ -20,6 +20,7 @@
 #include <sHT/resource.h>
 #include <sHT/scheduling.h>
 #include <sHT/stream.h>
+#include <sHT/test.h>
 
 #include <errno.h>
 #include <stddef.h>
@@ -39,7 +40,7 @@ sHTTPd_close_connection(struct sHT_worker *worker, struct sHT_task_stream *task)
 void
 sHT_socket_task(struct sHT_worker *worker, struct sHT_task_stream *task)
 {
-	if (sHT_test_hidden(task->task.epollflags, !(task->task.epollflags & (EPOLLIN | EPOLLOUT))))
+	if (!sHT_and_any(task->task.epollflags, EPOLLIN | EPOLLOUT))
 		return;
 
 	/* @var{sHT_socket_mayread} and @var{sHT_socket_maywrite} don't
@@ -56,13 +57,13 @@ sHT_socket_task(struct sHT_worker *worker, struct sHT_task_stream *task)
 		sHT_socket_sendsome_tcp(worker, task);
 	/* TODO: do HTTP */
 	/* A graceful shutdown */
-	if (sHT_test_hidden(task->stream.to_write.length, task->stream.to_write.length == 0))
+	if (sHT_zero_p(task->stream.to_write.length))
 		/* The file descriptor remains intact, so no Spectre issues */
 		shutdown(task->stream.fd, SHUT_WR);
 
-	if (sHT_test_hidden(task->stream.flags, task->stream.flags & (sHT_STREAM_RESET_GRACEFUL | sHT_STREAM_RESET_BLUNT | sHT_STREAM_WRITE_EOF | sHTTPd_DONE)))
+	if (sHT_and_any(task->stream.flags, sHT_STREAM_RESET_GRACEFUL | sHT_STREAM_RESET_BLUNT | sHT_STREAM_WRITE_EOF | sHTTPd_DONE))
 		sHTTPd_close_connection(worker, task);
-	if (sHT_test_hidden(task->task.flags, task->task.flags & sHT_TASK_SCHEDULE)) {
+	if (sHT_and_any(task->task.flags, sHT_TASK_SCHEDULE)) {
 		task->task.flags &= ~sHT_TASK_SCHEDULE;
 		sHT_qadd_try(&worker->todo.queue, &task->task);
 	}

+ 46 - 0
sHT/bitvec.h

@@ -0,0 +1,46 @@
+/* s^2 - array of bits
+   Copyright (C) 2018 Ariadne Devos
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _sHT_BITVEC_H
+#define _sHT_BITVEC_H
+
+#include <stdint.h>
+#include <sHT/test.h>
+
+/** Test if a bit is set.
+
+  @var{bits}: a bit array. Bits are numbered from the first byte to the last,
+    from the least-significant bit to the most-significant.
+  @var{index}: the index of the bit. It is within bounds.
+
+  The bit should be set more often than it is not.
+  No bounds checking is performed. This must be called in control position. */
+__attribute__((always_inline))
+__attribute__((pure))
+static inline _Bool
+sHT_bit_test(const uint8_t *bits, unsigned int index)
+{
+	/* x86 has a special instruction for testing a bit (bt), which GCC
+	   doesn't generate automatically, but it is tricky to use -- as of
+	   now, to no avail. There are tests for the courageous, in
+	   <tests/bitvec.c>.
+
+	   There seems to be no code size difference in
+	   different choices of uintN_t. */
+        return sHT_and_any(bits[index / 8], 1u << (index % 8));
+}
+
+#endif

+ 4 - 0
sHT/compiler.h

@@ -22,6 +22,10 @@
 #define sHT_likely(b) (__builtin_expect(!!(b), 1))
 #define sHT_unlikely(b) (__builtin_expect(!!(b), 0))
 
+/** Can the compiler prove @var{u} is a constant?
+  There may be false negatives. */
+#define sHT_constant_p(u) __builtin_constant_p(u)
+
 /* Let the compiler forget the value of the variable var.
    This does not avoid speculation by the processor.
    For Spectre mitigations, consider sHT_despeculate.

+ 0 - 0
sHT/scheduling.h


Some files were not shown because too many files changed in this diff