]> granicus.if.org Git - strace/commitdiff
prctl: add PR_GET_SPECULATION_CTRL/PR_SET_SPECULATION_CTRL decoding
authorEugene Syromyatnikov <evgsyr@gmail.com>
Tue, 22 May 2018 17:13:30 +0000 (19:13 +0200)
committerDmitry V. Levin <ldv@altlinux.org>
Fri, 25 May 2018 09:15:03 +0000 (09:15 +0000)
* xlat/pr_spec_cmds.in: New fille.
* xlat/pr_spec_get_store_bypass_flags.in: Likewise.
* xlat/pr_spec_set_store_bypass_flags.in: Likewise.
* xlat/prctl_options.in (PR_GET_SPECULATION_CTRL,
PR_SET_SPECULATION_CTRL): New constants, introduced by Linux commit
v4.17-rc3-15-gb617cfc.
* prctl.c (SYS_FUNC(prctl)) <case PR_GET_SPECULATION_CTRL,
case PR_SET_SPECULATION_CTRL>: Implement decoding of new prctl options.
* tests/Makefile.am (check_PROGRAMS): Add prctl-spec-inject.
(DECODER_TESTS): Add prctl-spec-inject.test.
* tests/prctl-spec-inject.c: New file.
* tests/prctl-spec-inject.test: New test.
* tests/.gitignore: Add prctl-spec-inject.

prctl.c
tests/.gitignore
tests/Makefile.am
tests/prctl-spec-inject.c [new file with mode: 0644]
tests/prctl-spec-inject.test [new file with mode: 0755]
xlat/pr_spec_cmds.in [new file with mode: 0644]
xlat/pr_spec_get_store_bypass_flags.in [new file with mode: 0644]
xlat/pr_spec_set_store_bypass_flags.in [new file with mode: 0644]
xlat/prctl_options.in

diff --git a/prctl.c b/prctl.c
index 801e7b5a8444d964c00c8561041a1d0cc3c7d73e..568b5f7dfb622eee383bfa73a4f88e604e270c6d 100644 (file)
--- a/prctl.c
+++ b/prctl.c
@@ -42,6 +42,9 @@
 #include "xlat/pr_mce_kill.h"
 #include "xlat/pr_mce_kill_policy.h"
 #include "xlat/pr_set_mm.h"
+#include "xlat/pr_spec_cmds.h"
+#include "xlat/pr_spec_get_store_bypass_flags.h"
+#include "xlat/pr_spec_set_store_bypass_flags.h"
 #include "xlat/pr_sve_vl_flags.h"
 #include "xlat/pr_tsc.h"
 #include "xlat/pr_unalign_flags.h"
@@ -225,6 +228,27 @@ SYS_FUNC(prctl)
 
                return RVAL_STR;
 
+       case PR_GET_SPECULATION_CTRL:
+               if (entering(tcp)) {
+                       tprints(", ");
+                       printxval64(pr_spec_cmds, arg2, "PR_SPEC_???");
+
+                       break;
+               }
+
+               if (syserror(tcp))
+                       return 0;
+
+               switch (arg2) {
+               case PR_SPEC_STORE_BYPASS:
+                       tcp->auxstr = sprintflags("",
+                                                 pr_spec_get_store_bypass_flags,
+                                                 (kernel_ulong_t) tcp->u_rval);
+                       break;
+               }
+
+               return RVAL_STR;
+
        /* PR_TASK_PERF_EVENTS_* take no arguments. */
        case PR_TASK_PERF_EVENTS_DISABLE:
        case PR_TASK_PERF_EVENTS_ENABLE:
@@ -382,6 +406,23 @@ SYS_FUNC(prctl)
                printflags(pr_fp_mode, arg2, "PR_FP_MODE_???");
                return RVAL_DECODED;
 
+       case PR_SET_SPECULATION_CTRL:
+               tprints(", ");
+               printxval64(pr_spec_cmds, arg2, "PR_SPEC_???");
+               tprints(", ");
+
+               switch (arg2) {
+               case PR_SPEC_STORE_BYPASS:
+                       printxval64(pr_spec_set_store_bypass_flags, arg3,
+                                   "PR_SPEC_???");
+                       break;
+
+               default:
+                       tprintf("%#" PRI_klx, arg3);
+               }
+
+               return RVAL_DECODED;
+
        case PR_GET_NO_NEW_PRIVS:
        case PR_GET_THP_DISABLE:
        case PR_MPX_DISABLE_MANAGEMENT:
index b39db931b71ef0bdd4d4a38b9e6a3523cf738119..5c46811279fe330b975fa1156f3a597e0a15b38a 100644 (file)
@@ -346,6 +346,7 @@ prctl-pdeathsig
 prctl-seccomp-filter-v
 prctl-seccomp-strict
 prctl-securebits
+prctl-spec-inject
 prctl-tid_address
 prctl-tsc
 pread64-pwrite64
index 8f676570b45ed3f5817fba5afe0d2c5553f1b05d..92be1e8bf777d1dc05635704985d64c07f8ab83e 100644 (file)
@@ -137,6 +137,7 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
        ppoll-v \
        prctl-seccomp-filter-v \
        prctl-seccomp-strict \
+       prctl-spec-inject \
        print_maxfd \
        qual_fault \
        qual_inject-error-signal \
@@ -258,6 +259,7 @@ DECODER_TESTS = \
        prctl-seccomp-filter-v.test \
        prctl-seccomp-strict.test \
        prctl-securebits.test \
+       prctl-spec-inject.test \
        prctl-tid_address.test \
        prctl-tsc.test \
        qual_fault-exit_group.test \
diff --git a/tests/prctl-spec-inject.c b/tests/prctl-spec-inject.c
new file mode 100644 (file)
index 0000000..593c3a6
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Check decoding of PR_SET_SPECULATION_CTRL and PR_GET_SPECULATION_CTRL
+ * prctl operations.
+ *
+ * Copyright (c) 2018 The strace developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests.h"
+#include <asm/unistd.h>
+
+#ifdef __NR_prctl
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <linux/prctl.h>
+
+static long injected_val;
+
+long
+do_prctl(kernel_ulong_t cmd, kernel_ulong_t arg2, kernel_ulong_t arg3)
+{
+       long rc = syscall(__NR_prctl, cmd, arg2, arg3);
+
+       if (rc != injected_val)
+               error_msg_and_fail("Return value (%ld) differs from expected "
+                                  "injected value (%ld)",
+                                  rc, injected_val);
+
+       return rc;
+}
+
+int
+main(int argc, char **argv)
+{
+       static const kernel_ulong_t bogus_arg2 =
+               (kernel_ulong_t) 0xdeadfacebadc0dedULL;
+       static const kernel_ulong_t bogus_arg3 =
+               (kernel_ulong_t) 0xdecafeedbeefda7eULL;
+       static const struct {
+               long arg;
+               const char *str;
+       } get_strs[] = {
+               { -1, "" },
+               { 0, " (PR_SPEC_NOT_AFFECTED)" },
+               { 1, " (PR_SPEC_PRCTL)" },
+               { 3, " (PR_SPEC_PRCTL|PR_SPEC_ENABLE)" },
+               { 8, " (PR_SPEC_FORCE_DISABLE)" },
+               { 16, " (0x10)" },
+               { 42, " (PR_SPEC_ENABLE|PR_SPEC_FORCE_DISABLE|0x20)" },
+       };
+       static const struct {
+               kernel_ulong_t arg;
+               const char *str;
+       } set_strs[] = {
+               { 0, "0 /* PR_SPEC_??? */" },
+               { 1, "0x1 /* PR_SPEC_??? */" },
+               { 2, "PR_SPEC_ENABLE" },
+               { 3, "0x3 /* PR_SPEC_??? */" },
+               { 8, "PR_SPEC_FORCE_DISABLE" },
+               { 16, "0x10 /* PR_SPEC_??? */" },
+               { (kernel_ulong_t) 0xdecafeedbeefda7eULL, "0x"
+# if SIZEOF_KERNEL_LONG_T == 8
+                       "decafeed"
+# endif
+                       "beefda7e /* PR_SPEC_??? */" },
+       };
+
+       long rc;
+       const char *str = NULL;
+
+       if (argc < 2)
+               error_msg_and_fail("Usage: %s INJECTED_VAL", argv[0]);
+
+       injected_val = strtol(argv[1], NULL, 0);
+
+       /* PR_GET_SPECULATION_CTRL */
+       rc = do_prctl(52, 1, bogus_arg3);
+       printf("prctl(PR_GET_SPECULATION_CTRL, 0x1 /* PR_SPEC_??? */) "
+              "= %s (INJECTED)\n", sprintrc(rc));
+
+       rc = do_prctl(52, bogus_arg2, bogus_arg3);
+       printf("prctl(PR_GET_SPECULATION_CTRL, %#llx /* PR_SPEC_??? */) "
+              "= %s (INJECTED)\n",
+              (unsigned long long) bogus_arg2, sprintrc(rc));
+
+       rc = do_prctl(52, 0, bogus_arg3);
+
+       for (unsigned i = 0; i < ARRAY_SIZE(get_strs); i++) {
+               if (get_strs[i].arg == rc) {
+                       str = get_strs[i].str;
+                       break;
+               }
+       }
+       if (!str)
+               error_msg_and_fail("Unknown return value: %ld", rc);
+
+       printf("prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS) "
+              "= %s%s (INJECTED)\n", sprintrc(rc), str);
+
+
+       /* PR_SET_SPECULATION_CTRL*/
+       rc = do_prctl(53, 1, bogus_arg3);
+       printf("prctl(PR_SET_SPECULATION_CTRL, 0x1 /* PR_SPEC_??? */, %#llx) "
+              "= %s (INJECTED)\n",
+              (unsigned long long) bogus_arg3, sprintrc(rc));
+
+       rc = do_prctl(53, bogus_arg2, bogus_arg3);
+       printf("prctl(PR_SET_SPECULATION_CTRL, %#llx /* PR_SPEC_??? */, %#llx) "
+              "= %s (INJECTED)\n",
+              (unsigned long long) bogus_arg2,
+              (unsigned long long) bogus_arg3,
+              sprintrc(rc));
+
+       for (unsigned i = 0; i < ARRAY_SIZE(set_strs); i++) {
+               rc = do_prctl(53, 0, set_strs[i].arg);
+               printf("prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS"
+                      ", %s) = %s (INJECTED)\n",
+                      set_strs[i].str, sprintrc(rc));
+       }
+
+       puts("+++ exited with 0 +++");
+       return 0;
+}
+
+#else
+
+SKIP_MAIN_UNDEFINED("__NR_prctl")
+
+#endif
diff --git a/tests/prctl-spec-inject.test b/tests/prctl-spec-inject.test
new file mode 100755 (executable)
index 0000000..328b7ed
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh -efu
+
+. "${srcdir=.}/scno_tampering.sh"
+
+fault_args='-a53 -e trace=prctl -e inject=prctl:'
+prog="../$NAME"
+
+test_run_rval()
+{
+       local run rval injexpr
+       run="$1"; shift
+       rval="$1"; shift
+       injexpr="$1"; shift
+
+       run_strace $fault_args$injexpr $prog $rval > "$EXP"
+       LC_ALL=C grep -Ev '^prctl\(PR_[GS]ET_([^S][^P][^E][^C]])' \
+               < "$LOG" > "$OUT"
+       match_diff "$OUT" "$EXP"
+}
+
+test_run_rval 0 -1 "error=ENOTTY"
+test_run_rval 1 0 "retval=0"
+test_run_rval 2 1 "retval=1"
+test_run_rval 3 3 "retval=3"
+test_run_rval 4 8 "retval=8"
+test_run_rval 5 16 "retval=16"
+test_run_rval 6 42 "retval=42"
diff --git a/xlat/pr_spec_cmds.in b/xlat/pr_spec_cmds.in
new file mode 100644 (file)
index 0000000..e006923
--- /dev/null
@@ -0,0 +1 @@
+PR_SPEC_STORE_BYPASS   0
diff --git a/xlat/pr_spec_get_store_bypass_flags.in b/xlat/pr_spec_get_store_bypass_flags.in
new file mode 100644 (file)
index 0000000..81f3674
--- /dev/null
@@ -0,0 +1,5 @@
+PR_SPEC_NOT_AFFECTED   0
+PR_SPEC_PRCTL          (1 << 0)
+PR_SPEC_ENABLE         (1 << 1)
+PR_SPEC_DISABLE                (1 << 2)
+PR_SPEC_FORCE_DISABLE  (1 << 3)
diff --git a/xlat/pr_spec_set_store_bypass_flags.in b/xlat/pr_spec_set_store_bypass_flags.in
new file mode 100644 (file)
index 0000000..04f3a03
--- /dev/null
@@ -0,0 +1,3 @@
+PR_SPEC_ENABLE         (1 << 1)
+PR_SPEC_DISABLE                (1 << 2)
+PR_SPEC_FORCE_DISABLE  (1 << 3)
index 86fcd2cd42b1deaa84fc2d013c2cf0ec4985ad19..82787e339a583c36878656ff50d94c5cca794309 100644 (file)
@@ -46,4 +46,6 @@ PR_GET_FP_MODE 46
 PR_CAP_AMBIENT 47
 PR_SVE_SET_VL 50
 PR_SVE_GET_VL 51
+PR_GET_SPECULATION_CTRL 52
+PR_SET_SPECULATION_CTRL 53
 PR_SET_VMA 0x53564d41