summaryrefslogtreecommitdiff
path: root/tools/testing
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/nvdimm/Kbuild3
-rw-r--r--tools/testing/nvdimm/dimm_devs.c41
-rw-r--r--tools/testing/nvdimm/test/iomap.c17
-rw-r--r--tools/testing/nvdimm/test/nfit.c321
-rw-r--r--tools/testing/selftests/Makefile3
-rw-r--r--tools/testing/selftests/drivers/dma-buf/Makefile2
-rw-r--r--tools/testing/selftests/drivers/dma-buf/udmabuf.c11
-rw-r--r--tools/testing/selftests/firmware/config1
-rwxr-xr-xtools/testing/selftests/firmware/fw_filesystem.sh9
-rw-r--r--tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc30
-rw-r--r--tools/testing/selftests/ftrace/test.d/dynevent/add_remove_synth.tc27
-rw-r--r--tools/testing/selftests/ftrace/test.d/dynevent/clear_select_events.tc50
-rw-r--r--tools/testing/selftests/ftrace/test.d/dynevent/generic_clear_event.tc49
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func-filter-stacktrace.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_cpumask.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/template2
-rw-r--r--tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc2
-rw-r--r--tools/testing/selftests/gpio/Makefile10
-rw-r--r--tools/testing/selftests/ima/Makefile11
-rw-r--r--tools/testing/selftests/ima/config4
-rwxr-xr-xtools/testing/selftests/ima/test_kexec_load.sh54
-rw-r--r--tools/testing/selftests/ir/.gitignore1
-rw-r--r--tools/testing/selftests/ir/Makefile5
-rw-r--r--tools/testing/selftests/ir/ir_loopback.c199
-rwxr-xr-xtools/testing/selftests/ir/ir_loopback.sh20
-rw-r--r--tools/testing/selftests/kselftest_harness.h42
-rw-r--r--tools/testing/selftests/seccomp/seccomp_bpf.c447
-rw-r--r--tools/testing/selftests/watchdog/watchdog-test.c13
29 files changed, 1339 insertions, 41 deletions
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index 778ceb651000..10ddf223055b 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -37,6 +37,7 @@ obj-$(CONFIG_DEV_DAX) += device_dax.o
obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
nfit-y := $(ACPI_SRC)/core.o
+nfit-y += $(ACPI_SRC)/intel.o
nfit-$(CONFIG_X86_MCE) += $(ACPI_SRC)/mce.o
nfit-y += acpi_nfit_test.o
nfit-y += config_check.o
@@ -79,6 +80,8 @@ libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o
libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o
libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o
libnvdimm-$(CONFIG_NVDIMM_DAX) += $(NVDIMM_SRC)/dax_devs.o
+libnvdimm-$(CONFIG_NVDIMM_KEYS) += $(NVDIMM_SRC)/security.o
+libnvdimm-y += dimm_devs.o
libnvdimm-y += libnvdimm_test.o
libnvdimm-y += config_check.o
diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c
new file mode 100644
index 000000000000..e75238404555
--- /dev/null
+++ b/tools/testing/nvdimm/dimm_devs.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Intel Corp. 2018 */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/nd.h>
+#include "pmem.h"
+#include "pfn.h"
+#include "nd.h"
+#include "nd-core.h"
+
+ssize_t security_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+
+ /*
+ * For the test version we need to poll the "hardware" in order
+ * to get the updated status for unlock testing.
+ */
+ nvdimm->sec.state = nvdimm_security_state(nvdimm, false);
+ nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, true);
+
+ switch (nvdimm->sec.state) {
+ case NVDIMM_SECURITY_DISABLED:
+ return sprintf(buf, "disabled\n");
+ case NVDIMM_SECURITY_UNLOCKED:
+ return sprintf(buf, "unlocked\n");
+ case NVDIMM_SECURITY_LOCKED:
+ return sprintf(buf, "locked\n");
+ case NVDIMM_SECURITY_FROZEN:
+ return sprintf(buf, "frozen\n");
+ case NVDIMM_SECURITY_OVERWRITE:
+ return sprintf(buf, "overwrite\n");
+ default:
+ return -ENOTTY;
+ }
+
+ return -ENOTTY;
+}
+
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index ff9d3a5825e1..c6635fee27d8 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -104,16 +104,29 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
}
EXPORT_SYMBOL(__wrap_devm_memremap);
+static void nfit_test_kill(void *_pgmap)
+{
+ struct dev_pagemap *pgmap = _pgmap;
+
+ pgmap->kill(pgmap->ref);
+}
+
void *__wrap_devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
{
resource_size_t offset = pgmap->res.start;
struct nfit_test_resource *nfit_res = get_nfit_res(offset);
- if (nfit_res)
+ if (nfit_res) {
+ int rc;
+
+ rc = devm_add_action_or_reset(dev, nfit_test_kill, pgmap);
+ if (rc)
+ return ERR_PTR(rc);
return nfit_res->buf + offset - nfit_res->res.start;
+ }
return devm_memremap_pages(dev, pgmap);
}
-EXPORT_SYMBOL(__wrap_devm_memremap_pages);
+EXPORT_SYMBOL_GPL(__wrap_devm_memremap_pages);
pfn_t __wrap_phys_to_pfn_t(phys_addr_t addr, unsigned long flags)
{
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 6c16ac36d482..b579f962451d 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -143,6 +143,13 @@ static u32 handle[] = {
static unsigned long dimm_fail_cmd_flags[ARRAY_SIZE(handle)];
static int dimm_fail_cmd_code[ARRAY_SIZE(handle)];
+struct nfit_test_sec {
+ u8 state;
+ u8 ext_state;
+ u8 passphrase[32];
+ u8 master_passphrase[32];
+ u64 overwrite_end_time;
+} dimm_sec_info[NUM_DCR];
static const struct nd_intel_smart smart_def = {
.flags = ND_INTEL_SMART_HEALTH_VALID
@@ -936,6 +943,242 @@ static int override_return_code(int dimm, unsigned int func, int rc)
return rc;
}
+static int nd_intel_test_cmd_security_status(struct nfit_test *t,
+ struct nd_intel_get_security_state *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ nd_cmd->status = 0;
+ nd_cmd->state = sec->state;
+ nd_cmd->extended_state = sec->ext_state;
+ dev_dbg(dev, "security state (%#x) returned\n", nd_cmd->state);
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_unlock_unit(struct nfit_test *t,
+ struct nd_intel_unlock_unit *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_LOCKED) ||
+ (sec->state & ND_INTEL_SEC_STATE_FROZEN)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "unlock unit: invalid state: %#x\n",
+ sec->state);
+ } else if (memcmp(nd_cmd->passphrase, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "unlock unit: invalid passphrase\n");
+ } else {
+ nd_cmd->status = 0;
+ sec->state = ND_INTEL_SEC_STATE_ENABLED;
+ dev_dbg(dev, "Unit unlocked\n");
+ }
+
+ dev_dbg(dev, "unlocking status returned: %#x\n", nd_cmd->status);
+ return 0;
+}
+
+static int nd_intel_test_cmd_set_pass(struct nfit_test *t,
+ struct nd_intel_set_passphrase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (sec->state & ND_INTEL_SEC_STATE_FROZEN) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "set passphrase: wrong security state\n");
+ } else if (memcmp(nd_cmd->old_pass, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "set passphrase: wrong passphrase\n");
+ } else {
+ memcpy(sec->passphrase, nd_cmd->new_pass,
+ ND_INTEL_PASSPHRASE_SIZE);
+ sec->state |= ND_INTEL_SEC_STATE_ENABLED;
+ nd_cmd->status = 0;
+ dev_dbg(dev, "passphrase updated\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_freeze_lock(struct nfit_test *t,
+ struct nd_intel_freeze_lock *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "freeze lock: wrong security state\n");
+ } else {
+ sec->state |= ND_INTEL_SEC_STATE_FROZEN;
+ nd_cmd->status = 0;
+ dev_dbg(dev, "security frozen\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_disable_pass(struct nfit_test *t,
+ struct nd_intel_disable_passphrase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) ||
+ (sec->state & ND_INTEL_SEC_STATE_FROZEN)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "disable passphrase: wrong security state\n");
+ } else if (memcmp(nd_cmd->passphrase, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "disable passphrase: wrong passphrase\n");
+ } else {
+ memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE);
+ sec->state = 0;
+ dev_dbg(dev, "disable passphrase: done\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_secure_erase(struct nfit_test *t,
+ struct nd_intel_secure_erase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) ||
+ (sec->state & ND_INTEL_SEC_STATE_FROZEN)) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "secure erase: wrong security state\n");
+ } else if (memcmp(nd_cmd->passphrase, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "secure erase: wrong passphrase\n");
+ } else {
+ memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE);
+ memset(sec->master_passphrase, 0, ND_INTEL_PASSPHRASE_SIZE);
+ sec->state = 0;
+ sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED;
+ dev_dbg(dev, "secure erase: done\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_overwrite(struct nfit_test *t,
+ struct nd_intel_overwrite *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if ((sec->state & ND_INTEL_SEC_STATE_ENABLED) &&
+ memcmp(nd_cmd->passphrase, sec->passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "overwrite: wrong passphrase\n");
+ return 0;
+ }
+
+ memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE);
+ sec->state = ND_INTEL_SEC_STATE_OVERWRITE;
+ dev_dbg(dev, "overwrite progressing.\n");
+ sec->overwrite_end_time = get_jiffies_64() + 5 * HZ;
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_query_overwrite(struct nfit_test *t,
+ struct nd_intel_query_overwrite *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->state & ND_INTEL_SEC_STATE_OVERWRITE)) {
+ nd_cmd->status = ND_INTEL_STATUS_OQUERY_SEQUENCE_ERR;
+ return 0;
+ }
+
+ if (time_is_before_jiffies64(sec->overwrite_end_time)) {
+ sec->overwrite_end_time = 0;
+ sec->state = 0;
+ sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED;
+ dev_dbg(dev, "overwrite is complete\n");
+ } else
+ nd_cmd->status = ND_INTEL_STATUS_OQUERY_INPROGRESS;
+ return 0;
+}
+
+static int nd_intel_test_cmd_master_set_pass(struct nfit_test *t,
+ struct nd_intel_set_master_passphrase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->ext_state & ND_INTEL_SEC_ESTATE_ENABLED)) {
+ nd_cmd->status = ND_INTEL_STATUS_NOT_SUPPORTED;
+ dev_dbg(dev, "master set passphrase: in wrong state\n");
+ } else if (sec->ext_state & ND_INTEL_SEC_ESTATE_PLIMIT) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "master set passphrase: in wrong security state\n");
+ } else if (memcmp(nd_cmd->old_pass, sec->master_passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "master set passphrase: wrong passphrase\n");
+ } else {
+ memcpy(sec->master_passphrase, nd_cmd->new_pass,
+ ND_INTEL_PASSPHRASE_SIZE);
+ sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED;
+ dev_dbg(dev, "master passphrase: updated\n");
+ }
+
+ return 0;
+}
+
+static int nd_intel_test_cmd_master_secure_erase(struct nfit_test *t,
+ struct nd_intel_master_secure_erase *nd_cmd,
+ unsigned int buf_len, int dimm)
+{
+ struct device *dev = &t->pdev.dev;
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ if (!(sec->ext_state & ND_INTEL_SEC_ESTATE_ENABLED)) {
+ nd_cmd->status = ND_INTEL_STATUS_NOT_SUPPORTED;
+ dev_dbg(dev, "master secure erase: in wrong state\n");
+ } else if (sec->ext_state & ND_INTEL_SEC_ESTATE_PLIMIT) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE;
+ dev_dbg(dev, "master secure erase: in wrong security state\n");
+ } else if (memcmp(nd_cmd->passphrase, sec->master_passphrase,
+ ND_INTEL_PASSPHRASE_SIZE) != 0) {
+ nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS;
+ dev_dbg(dev, "master secure erase: wrong passphrase\n");
+ } else {
+ /* we do not erase master state passphrase ever */
+ sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED;
+ memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE);
+ sec->state = 0;
+ dev_dbg(dev, "master secure erase: done\n");
+ }
+
+ return 0;
+}
+
+
static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func)
{
int i;
@@ -983,6 +1226,46 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
return i;
switch (func) {
+ case NVDIMM_INTEL_GET_SECURITY_STATE:
+ rc = nd_intel_test_cmd_security_status(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_UNLOCK_UNIT:
+ rc = nd_intel_test_cmd_unlock_unit(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_SET_PASSPHRASE:
+ rc = nd_intel_test_cmd_set_pass(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_DISABLE_PASSPHRASE:
+ rc = nd_intel_test_cmd_disable_pass(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_FREEZE_LOCK:
+ rc = nd_intel_test_cmd_freeze_lock(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_SECURE_ERASE:
+ rc = nd_intel_test_cmd_secure_erase(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_OVERWRITE:
+ rc = nd_intel_test_cmd_overwrite(t,
+ buf, buf_len, i - t->dcr_idx);
+ break;
+ case NVDIMM_INTEL_QUERY_OVERWRITE:
+ rc = nd_intel_test_cmd_query_overwrite(t,
+ buf, buf_len, i - t->dcr_idx);
+ break;
+ case NVDIMM_INTEL_SET_MASTER_PASSPHRASE:
+ rc = nd_intel_test_cmd_master_set_pass(t,
+ buf, buf_len, i);
+ break;
+ case NVDIMM_INTEL_MASTER_SECURE_ERASE:
+ rc = nd_intel_test_cmd_master_secure_erase(t,
+ buf, buf_len, i);
+ break;
case ND_INTEL_ENABLE_LSS_STATUS:
rc = nd_intel_test_cmd_set_lss_status(t,
buf, buf_len);
@@ -1328,10 +1611,22 @@ static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *
}
static DEVICE_ATTR_RW(fail_cmd_code);
+static ssize_t lock_dimm_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ int dimm = dimm_name_to_id(dev);
+ struct nfit_test_sec *sec = &dimm_sec_info[dimm];
+
+ sec->state = ND_INTEL_SEC_STATE_ENABLED | ND_INTEL_SEC_STATE_LOCKED;
+ return size;
+}
+static DEVICE_ATTR_WO(lock_dimm);
+
static struct attribute *nfit_test_dimm_attributes[] = {
&dev_attr_fail_cmd.attr,
&dev_attr_fail_cmd_code.attr,
&dev_attr_handle.attr,
+ &dev_attr_lock_dimm.attr,
NULL,
};
@@ -1361,6 +1656,17 @@ static int nfit_test_dimm_init(struct nfit_test *t)
return 0;
}
+static void security_init(struct nfit_test *t)
+{
+ int i;
+
+ for (i = 0; i < t->num_dcr; i++) {
+ struct nfit_test_sec *sec = &dimm_sec_info[i];
+
+ sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED;
+ }
+}
+
static void smart_init(struct nfit_test *t)
{
int i;
@@ -1439,6 +1745,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
if (nfit_test_dimm_init(t))
return -ENOMEM;
smart_init(t);
+ security_init(t);
return ars_state_init(&t->pdev.dev, &t->ars_state);
}
@@ -2210,6 +2517,20 @@ static void nfit_test0_setup(struct nfit_test *t)
set_bit(ND_INTEL_FW_FINISH_UPDATE, &acpi_desc->dimm_cmd_force_en);
set_bit(ND_INTEL_FW_FINISH_QUERY, &acpi_desc->dimm_cmd_force_en);
set_bit(ND_INTEL_ENABLE_LSS_STATUS, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_GET_SECURITY_STATE,
+ &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_SET_PASSPHRASE, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE,
+ &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_UNLOCK_UNIT, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_FREEZE_LOCK, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_SECURE_ERASE, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_OVERWRITE, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_QUERY_OVERWRITE, &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_SET_MASTER_PASSPHRASE,
+ &acpi_desc->dimm_cmd_force_en);
+ set_bit(NVDIMM_INTEL_MASTER_SECURE_ERASE,
+ &acpi_desc->dimm_cmd_force_en);
}
static void nfit_test1_setup(struct nfit_test *t)
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 24b9934fb269..1a2bd15c5b6e 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -6,6 +6,7 @@ TARGETS += capabilities
TARGETS += cgroup
TARGETS += cpufreq
TARGETS += cpu-hotplug
+TARGETS += drivers/dma-buf
TARGETS += efivarfs
TARGETS += exec
TARGETS += filesystems
@@ -13,8 +14,10 @@ TARGETS += firmware
TARGETS += ftrace
TARGETS += futex
TARGETS += gpio
+TARGETS += ima
TARGETS += intel_pstate
TARGETS += ipc
+TARGETS += ir
TARGETS += kcmp
TARGETS += kvm
TARGETS += lib
diff --git a/tools/testing/selftests/drivers/dma-buf/Makefile b/tools/testing/selftests/drivers/dma-buf/Makefile
index 4154c3d7aa58..f22c3f7cf612 100644
--- a/tools/testing/selftests/drivers/dma-buf/Makefile
+++ b/tools/testing/selftests/drivers/dma-buf/Makefile
@@ -2,4 +2,6 @@ CFLAGS += -I../../../../../usr/include/
TEST_GEN_PROGS := udmabuf
+top_srcdir ?=../../../../..
+
include ../../lib.mk
diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c
index 376b1d6730bd..4de902ea14d8 100644
--- a/tools/testing/selftests/drivers/dma-buf/udmabuf.c
+++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c
@@ -4,7 +4,7 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <fcntl.h>
+#include <linux/fcntl.h>
#include <malloc.h>
#include <sys/ioctl.h>
@@ -33,12 +33,19 @@ int main(int argc, char *argv[])
exit(77);
}
- memfd = memfd_create("udmabuf-test", MFD_CLOEXEC);
+ memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
if (memfd < 0) {
printf("%s: [skip,no-memfd]\n", TEST_PREFIX);
exit(77);
}
+ ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
+ if (ret < 0) {
+ printf("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
+ exit(77);
+ }
+
+
size = getpagesize() * NUM_PAGES;
ret = ftruncate(memfd, size);
if (ret == -1) {
diff --git a/tools/testing/selftests/firmware/config b/tools/testing/selftests/firmware/config
index bf634dda0720..913a25a4a32b 100644
--- a/tools/testing/selftests/firmware/config
+++ b/tools/testing/selftests/firmware/config
@@ -1,5 +1,6 @@
CONFIG_TEST_FIRMWARE=y
CONFIG_FW_LOADER=y
CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
index a4320c4b44dc..466cf2f91ba0 100755
--- a/tools/testing/selftests/firmware/fw_filesystem.sh
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -155,11 +155,8 @@ read_firmwares()
{
for i in $(seq 0 3); do
config_set_read_fw_idx $i
- # Verify the contents are what we expect.
- # -Z required for now -- check for yourself, md5sum
- # on $FW and DIR/read_firmware will yield the same. Even
- # cmp agrees, so something is off.
- if ! diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then
+ # Verify the contents match
+ if ! diff -q "$FW" $DIR/read_firmware 2>/dev/null ; then
echo "request #$i: firmware was not loaded" >&2
exit 1
fi
@@ -171,7 +168,7 @@ read_firmwares_expect_nofile()
for i in $(seq 0 3); do
config_set_read_fw_idx $i
# Ensures contents differ
- if diff -q -Z "$FW" $DIR/read_firmware 2>/dev/null ; then
+ if diff -q "$FW" $DIR/read_firmware 2>/dev/null ; then
echo "request $i: file was not expected to match" >&2
exit 1
fi
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc
new file mode 100644
index 000000000000..c6d8387dbbb8
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc
@@ -0,0 +1,30 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Generic dynamic event - add/remove kprobe events
+
+[ -f dynamic_events ] || exit_unsupported
+
+grep -q "place: \[<module>:\]<symbol>" README || exit_unsupported
+grep -q "place (kretprobe): \[<module>:\]<symbol>" README || exit_unsupported
+
+echo 0 > events/enable
+echo > dynamic_events
+
+PLACE=_do_fork
+
+echo "p:myevent1 $PLACE" >> dynamic_events
+echo "r:myevent2 $PLACE" >> dynamic_events
+
+grep -q myevent1 dynamic_events
+grep -q myevent2 dynamic_events
+test -d events/kprobes/myevent1
+test -d events/kprobes/myevent2
+
+echo "-:myevent2" >> dynamic_events
+
+grep -q myevent1 dynamic_events
+! grep -q myevent2 dynamic_events
+
+echo > dynamic_events
+
+clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_synth.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_synth.tc
new file mode 100644
index 000000000000..62b77b5941d0
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_synth.tc
@@ -0,0 +1,27 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Generic dynamic event - add/remove synthetic events
+
+[ -f dynamic_events ] || exit_unsupported
+
+grep -q "s:\[synthetic/\]" README || exit_unsupported
+
+echo 0 > events/enable
+echo > dynamic_events
+
+echo "s:latency1 u64 lat; pid_t pid;" >> dynamic_events
+echo "s:latency2 u64 lat; pid_t pid;" >> dynamic_events
+
+grep -q latency1 dynamic_events
+grep -q latency2 dynamic_events
+test -d events/synthetic/latency1
+test -d events/synthetic/latency2
+
+echo "-:synthetic/latency2" >> dynamic_events
+
+grep -q latency1 dynamic_events
+! grep -q latency2 dynamic_events
+
+echo > dynamic_events
+
+clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/clear_select_events.tc b/tools/testing/selftests/ftrace/test.d/dynevent/clear_select_events.tc
new file mode 100644
index 000000000000..e0842109cb57
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/clear_select_events.tc
@@ -0,0 +1,50 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Generic dynamic event - selective clear (compatibility)
+
+[ -f dynamic_events ] || exit_unsupported
+
+grep -q "place: \[<module>:\]<symbol>" README || exit_unsupported
+grep -q "place (kretprobe): \[<module>:\]<symbol>" README || exit_unsupported
+
+grep -q "s:\[synthetic/\]" README || exit_unsupported
+
+[ -f synthetic_events ] || exit_unsupported
+[ -f kprobe_events ] || exit_unsupported
+
+echo 0 > events/enable
+echo > dynamic_events
+
+PLACE=_do_fork
+
+setup_events() {
+echo "p:myevent1 $PLACE" >> dynamic_events
+echo "s:latency1 u64 lat; pid_t pid;" >> dynamic_events
+echo "r:myevent2 $PLACE" >> dynamic_events
+echo "s:latency2 u64 lat; pid_t pid;" >> dynamic_events
+
+grep -q myevent1 dynamic_events
+grep -q myevent2 dynamic_events
+grep -q latency1 dynamic_events
+grep -q latency2 dynamic_events
+}
+
+setup_events
+echo > synthetic_events
+
+grep -q myevent1 dynamic_events
+grep -q myevent2 dynamic_events
+! grep -q latency1 dynamic_events
+! grep -q latency2 dynamic_events
+
+echo > dynamic_events
+
+setup_events
+echo > kprobe_events
+
+! grep -q myevent1 dynamic_events
+! grep -q myevent2 dynamic_events
+grep -q latency1 dynamic_events
+grep -q latency2 dynamic_events
+
+echo > dynamic_events
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/generic_clear_event.tc b/tools/testing/selftests/ftrace/test.d/dynevent/generic_clear_event.tc
new file mode 100644
index 000000000000..901922e97878
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/generic_clear_event.tc
@@ -0,0 +1,49 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Generic dynamic event - generic clear event
+
+[ -f dynamic_events ] || exit_unsupported
+
+grep -q "place: \[<module>:\]<symbol>" README || exit_unsupported
+grep -q "place (kretprobe): \[<module>:\]<symbol>" README || exit_unsupported
+
+grep -q "s:\[synthetic/\]" README || exit_unsupported
+
+echo 0 > events/enable
+echo > dynamic_events
+
+PLACE=_do_fork
+
+setup_events() {
+echo "p:myevent1 $PLACE" >> dynamic_events
+echo "s:latency1 u64 lat; pid_t pid;" >> dynamic_events
+echo "r:myevent2 $PLACE" >> dynamic_events
+echo "s:latency2 u64 lat; pid_t pid;" >> dynamic_events
+
+grep -q myevent1 dynamic_events
+grep -q myevent2 dynamic_events
+grep -q latency1 dynamic_events
+grep -q latency2 dynamic_events
+}
+
+setup_events
+
+echo "!p:myevent1 $PLACE" >> dynamic_events
+! grep -q myevent1 dynamic_events
+grep -q myevent2 dynamic_events
+grep -q latency1 dynamic_events
+grep -q latency2 dynamic_events
+
+echo "!s:latency1 u64 lat; pid_t pid;" >> dynamic_events
+grep -q myevent2 dynamic_events
+! grep -q latency1 dynamic_events
+grep -q latency2 dynamic_events
+
+echo "!r:myevent2 $PLACE" >> dynamic_events
+! grep -q myevent2 dynamic_events
+grep -q latency2 dynamic_events
+
+echo "!s:latency2 u64 lat; pid_t pid;" >> dynamic_events
+! grep -q latency2 dynamic_events
+
+echo > dynamic_events
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-stacktrace.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-stacktrace.tc
index bf72e783d014..36fb59f886ea 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-stacktrace.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-stacktrace.tc
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL2.0
+# SPDX-License-Identifier: GPL-2.0
# description: ftrace - stacktrace filter command
# flags: instance
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_cpumask.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_cpumask.tc
index 0e6810743576..86a1f07ef2ca 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/func_cpumask.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_cpumask.tc
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL2.0
+# SPDX-License-Identifier: GPL-2.0
# description: ftrace - function trace with cpumask
if ! which nproc ; then
diff --git a/tools/testing/selftests/ftrace/test.d/template b/tools/testing/selftests/ftrace/test.d/template
index 799da7e0b3c9..e1a5d14c4eaf 100644
--- a/tools/testing/selftests/ftrace/test.d/template
+++ b/tools/testing/selftests/ftrace/test.d/template
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL2.0
+# SPDX-License-Identifier: GPL-2.0
# description: %HERE DESCRIBE WHAT THIS DOES%
# you have to add ".tc" extention for your testcase file
# Note that all tests are run with "errexit" option.
diff --git a/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc b/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc
index e3005fa785f0..b0893d7edda3 100644
--- a/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc
+++ b/tools/testing/selftests/ftrace/test.d/tracer/wakeup.tc
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL2.0
+# SPDX-License-Identifier: GPL-2.0
# description: Test wakeup tracer
if ! which chrt ; then
diff --git a/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc b/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc
index f99b5178e00a..b9b6669a623b 100644
--- a/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc
+++ b/tools/testing/selftests/ftrace/test.d/tracer/wakeup_rt.tc
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL2.0
+# SPDX-License-Identifier: GPL-2.0
# description: Test wakeup RT tracer
if ! which chrt ; then
diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
index 07f572a1bd3f..0bb80619db58 100644
--- a/tools/testing/selftests/gpio/Makefile
+++ b/tools/testing/selftests/gpio/Makefile
@@ -1,7 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
-CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
-LDLIBS += -lmount -I/usr/include/libmount
+MOUNT_CFLAGS := $(shell pkg-config --cflags mount 2>/dev/null)
+MOUNT_LDLIBS := $(shell pkg-config --libs mount 2>/dev/null)
+ifeq ($(MOUNT_LDLIBS),)
+MOUNT_LDLIBS := -lmount -I/usr/include/libmount
+endif
+
+CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/ $(MOUNT_CFLAGS)
+LDLIBS += $(MOUNT_LDLIBS)
TEST_PROGS := gpio-mockup.sh
TEST_FILES := gpio-mockup-sysfs.sh
diff --git a/tools/testing/selftests/ima/Makefile b/tools/testing/selftests/ima/Makefile
new file mode 100644
index 000000000000..0b3adf5444b6
--- /dev/null
+++ b/tools/testing/selftests/ima/Makefile
@@ -0,0 +1,11 @@
+# Makefile for kexec_load
+
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
+
+ifeq ($(ARCH),x86)
+TEST_PROGS := test_kexec_load.sh
+
+include ../lib.mk
+
+endif
diff --git a/tools/testing/selftests/ima/config b/tools/testing/selftests/ima/config
new file mode 100644
index 000000000000..6bc86d4d9bb4
--- /dev/null
+++ b/tools/testing/selftests/ima/config
@@ -0,0 +1,4 @@
+CONFIG_IMA_APPRAISE
+CONFIG_IMA_ARCH_POLICY
+CONFIG_SECURITYFS
+CONFIG_KEXEC_VERIFY_SIG
diff --git a/tools/testing/selftests/ima/test_kexec_load.sh b/tools/testing/selftests/ima/test_kexec_load.sh
new file mode 100755
index 000000000000..1c10093fb526
--- /dev/null
+++ b/tools/testing/selftests/ima/test_kexec_load.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0+
+# Loading a kernel image via the kexec_load syscall should fail
+# when the kerne is CONFIG_KEXEC_VERIFY_SIG enabled and the system
+# is booted in secureboot mode.
+
+TEST="$0"
+EFIVARFS="/sys/firmware/efi/efivars"
+rc=0
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+
+# kexec requires root privileges
+if [ $UID != 0 ]; then
+ echo "$TEST: must be run as root" >&2
+ exit $ksft_skip
+fi
+
+# Make sure that efivars is mounted in the normal location
+if ! grep -q "^\S\+ $EFIVARFS efivarfs" /proc/mounts; then
+ echo "$TEST: efivars is not mounted on $EFIVARFS" >&2
+ exit $ksft_skip
+fi
+
+# Get secureboot mode
+file="$EFIVARFS/SecureBoot-*"
+if [ ! -e $file ]; then
+ echo "$TEST: unknown secureboot mode" >&2
+ exit $ksft_skip
+fi
+secureboot=`hexdump $file | awk '{print substr($4,length($4),1)}'`
+
+# kexec_load should fail in secure boot mode
+KERNEL_IMAGE="/boot/vmlinuz-`uname -r`"
+kexec -l $KERNEL_IMAGE &>> /dev/null
+if [ $? == 0 ]; then
+ kexec -u
+ if [ "$secureboot" == "1" ]; then
+ echo "$TEST: kexec_load succeeded [FAIL]"
+ rc=1
+ else
+ echo "$TEST: kexec_load succeeded [PASS]"
+ fi
+else
+ if [ "$secureboot" == "1" ]; then
+ echo "$TEST: kexec_load failed [PASS]"
+ else
+ echo "$TEST: kexec_load failed [FAIL]"
+ rc=1
+ fi
+fi
+
+exit $rc
diff --git a/tools/testing/selftests/ir/.gitignore b/tools/testing/selftests/ir/.gitignore
new file mode 100644
index 000000000000..070ea0c75fb8
--- /dev/null
+++ b/tools/testing/selftests/ir/.gitignore
@@ -0,0 +1 @@
+ir_loopback
diff --git a/tools/testing/selftests/ir/Makefile b/tools/testing/selftests/ir/Makefile
new file mode 100644
index 000000000000..f4ba8eb84b95
--- /dev/null
+++ b/tools/testing/selftests/ir/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_PROGS := ir_loopback.sh
+TEST_GEN_PROGS_EXTENDED := ir_loopback
+
+include ../lib.mk
diff --git a/tools/testing/selftests/ir/ir_loopback.c b/tools/testing/selftests/ir/ir_loopback.c
new file mode 100644
index 000000000000..858c19caf224
--- /dev/null
+++ b/tools/testing/selftests/ir/ir_loopback.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+// test ir decoder
+//
+// Copyright (C) 2018 Sean Young <sean@mess.org>
+
+// When sending LIRC_MODE_SCANCODE, the IR will be encoded. rc-loopback
+// will send this IR to the receiver side, where we try to read the decoded
+// IR. Decoding happens in a separate kernel thread, so we will need to
+// wait until that is scheduled, hence we use poll to check for read
+// readiness.
+
+#include <linux/lirc.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "../kselftest.h"
+
+#define TEST_SCANCODES 10
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static const struct {
+ enum rc_proto proto;
+ const char *name;
+ unsigned int mask;
+ const char *decoder;
+} protocols[] = {
+ { RC_PROTO_RC5, "rc-5", 0x1f7f, "rc-5" },
+ { RC_PROTO_RC5X_20, "rc-5x-20", 0x1f7f3f, "rc-5" },
+ { RC_PROTO_RC5_SZ, "rc-5-sz", 0x2fff, "rc-5-sz" },
+ { RC_PROTO_JVC, "jvc", 0xffff, "jvc" },
+ { RC_PROTO_SONY12, "sony-12", 0x1f007f, "sony" },
+ { RC_PROTO_SONY15, "sony-15", 0xff007f, "sony" },
+ { RC_PROTO_SONY20, "sony-20", 0x1fff7f, "sony" },
+ { RC_PROTO_NEC, "nec", 0xffff, "nec" },
+ { RC_PROTO_NECX, "nec-x", 0xffffff, "nec" },
+ { RC_PROTO_NEC32, "nec-32", 0xffffffff, "nec" },
+ { RC_PROTO_SANYO, "sanyo", 0x1fffff, "sanyo" },
+ { RC_PROTO_RC6_0, "rc-6-0", 0xffff, "rc-6" },
+ { RC_PROTO_RC6_6A_20, "rc-6-6a-20", 0xfffff, "rc-6" },
+ { RC_PROTO_RC6_6A_24, "rc-6-6a-24", 0xffffff, "rc-6" },
+ { RC_PROTO_RC6_6A_32, "rc-6-6a-32", 0xffffffff, "rc-6" },
+ { RC_PROTO_RC6_MCE, "rc-6-mce", 0x00007fff, "rc-6" },
+ { RC_PROTO_SHARP, "sharp", 0x1fff, "sharp" },
+};
+
+int lirc_open(const char *rc)
+{
+ struct dirent *dent;
+ char buf[100];
+ DIR *d;
+ int fd;
+
+ snprintf(buf, sizeof(buf), "/sys/class/rc/%s", rc);
+
+ d = opendir(buf);
+ if (!d)
+ ksft_exit_fail_msg("cannot open %s: %m\n", buf);
+
+ while ((dent = readdir(d)) != NULL) {
+ if (!strncmp(dent->d_name, "lirc", 4)) {
+ snprintf(buf, sizeof(buf), "/dev/%s", dent->d_name);
+ break;
+ }
+ }
+
+ if (!dent)
+ ksft_exit_fail_msg("cannot find lirc device for %s\n", rc);
+
+ closedir(d);
+
+ fd = open(buf, O_RDWR | O_NONBLOCK);
+ if (fd == -1)
+ ksft_exit_fail_msg("cannot open: %s: %m\n", buf);
+
+ return fd;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned int mode;
+ char buf[100];
+ int rlircfd, wlircfd, protocolfd, i, n;
+
+ srand(time(NULL));
+
+ if (argc != 3)
+ ksft_exit_fail_msg("Usage: %s <write rcN> <read rcN>\n",
+ argv[0]);
+
+ rlircfd = lirc_open(argv[2]);
+ mode = LIRC_MODE_SCANCODE;
+ if (ioctl(rlircfd, LIRC_SET_REC_MODE, &mode))
+ ksft_exit_fail_msg("failed to set scancode rec mode %s: %m\n",
+ argv[2]);
+
+ wlircfd = lirc_open(argv[1]);
+ if (ioctl(wlircfd, LIRC_SET_SEND_MODE, &mode))
+ ksft_exit_fail_msg("failed to set scancode send mode %s: %m\n",
+ argv[1]);
+
+ snprintf(buf, sizeof(buf), "/sys/class/rc/%s/protocols", argv[2]);
+ protocolfd = open(buf, O_WRONLY);
+ if (protocolfd == -1)
+ ksft_exit_fail_msg("failed to open %s: %m\n", buf);
+
+ printf("Sending IR on %s and receiving IR on %s.\n", argv[1], argv[2]);
+
+ for (i = 0; i < ARRAY_SIZE(protocols); i++) {
+ if (write(protocolfd, protocols[i].decoder,
+ strlen(protocols[i].decoder)) == -1)
+ ksft_exit_fail_msg("failed to set write decoder\n");
+
+ printf("Testing protocol %s for decoder %s (%d/%d)...\n",
+ protocols[i].name, protocols[i].decoder,
+ i + 1, (int)ARRAY_SIZE(protocols));
+
+ for (n = 0; n < TEST_SCANCODES; n++) {
+ unsigned int scancode = rand() & protocols[i].mask;
+ unsigned int rc_proto = protocols[i].proto;
+
+ if (rc_proto == RC_PROTO_RC6_MCE)
+ scancode |= 0x800f0000;
+
+ if (rc_proto == RC_PROTO_NECX &&
+ (((scancode >> 16) ^ ~(scancode >> 8)) & 0xff) == 0)
+ continue;
+
+ if (rc_proto == RC_PROTO_NEC32 &&
+ (((scancode >> 8) ^ ~scancode) & 0xff) == 0)
+ continue;
+
+ struct lirc_scancode lsc = {
+ .rc_proto = rc_proto,
+ .scancode = scancode
+ };
+
+ printf("Testing scancode:%x\n", scancode);
+
+ while (write(wlircfd, &lsc, sizeof(lsc)) < 0) {
+ if (errno == EINTR)
+ continue;
+
+ ksft_exit_fail_msg("failed to send ir: %m\n");
+ }
+
+ struct pollfd pfd = { .fd = rlircfd, .events = POLLIN };
+ struct lirc_scancode lsc2;
+
+ poll(&pfd, 1, 1000);
+
+ bool decoded = true;
+
+ while (read(rlircfd, &lsc2, sizeof(lsc2)) < 0) {
+ if (errno == EINTR)
+ continue;
+
+ ksft_test_result_error("no scancode decoded: %m\n");
+ decoded = false;
+ break;
+ }
+
+ if (!decoded)
+ continue;
+
+ if (lsc.rc_proto != lsc2.rc_proto)
+ ksft_test_result_error("decoded protocol is different: %d\n",
+ lsc2.rc_proto);
+
+ else if (lsc.scancode != lsc2.scancode)
+ ksft_test_result_error("decoded scancode is different: %llx\n",
+ lsc2.scancode);
+ else
+ ksft_inc_pass_cnt();
+ }
+
+ printf("OK\n");
+ }
+
+ close(rlircfd);
+ close(wlircfd);
+ close(protocolfd);
+
+ if (ksft_get_fail_cnt() > 0)
+ ksft_exit_fail();
+ else
+ ksft_exit_pass();
+
+ return 0;
+}
diff --git a/tools/testing/selftests/ir/ir_loopback.sh b/tools/testing/selftests/ir/ir_loopback.sh
new file mode 100755
index 000000000000..0a0b8dfa39be
--- /dev/null
+++ b/tools/testing/selftests/ir/ir_loopback.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+
+if ! /sbin/modprobe -q -n rc-loopback; then
+ echo "ir_loopback: module rc-loopback is not found [SKIP]"
+ exit $ksft_skip
+fi
+
+/sbin/modprobe rc-loopback
+if [ $? -ne 0 ]; then
+ exit
+fi
+
+RCDEV=$(grep -l DRV_NAME=rc-loopback /sys/class/rc/rc*/uevent | grep -o 'rc[0-9]\+')
+
+./ir_loopback $RCDEV $RCDEV
+exit
diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
index 6ae3730c4ee3..76d654ef3234 100644
--- a/tools/testing/selftests/kselftest_harness.h
+++ b/tools/testing/selftests/kselftest_harness.h
@@ -354,7 +354,7 @@
* ASSERT_EQ(expected, measured): expected == measured
*/
#define ASSERT_EQ(expected, seen) \
- __EXPECT(expected, seen, ==, 1)
+ __EXPECT(expected, #expected, seen, #seen, ==, 1)
/**
* ASSERT_NE(expected, seen)
@@ -365,7 +365,7 @@
* ASSERT_NE(expected, measured): expected != measured
*/
#define ASSERT_NE(expected, seen) \
- __EXPECT(expected, seen, !=, 1)
+ __EXPECT(expected, #expected, seen, #seen, !=, 1)
/**
* ASSERT_LT(expected, seen)
@@ -376,7 +376,7 @@
* ASSERT_LT(expected, measured): expected < measured
*/
#define ASSERT_LT(expected, seen) \
- __EXPECT(expected, seen, <, 1)
+ __EXPECT(expected, #expected, seen, #seen, <, 1)
/**
* ASSERT_LE(expected, seen)
@@ -387,7 +387,7 @@
* ASSERT_LE(expected, measured): expected <= measured
*/
#define ASSERT_LE(expected, seen) \
- __EXPECT(expected, seen, <=, 1)
+ __EXPECT(expected, #expected, seen, #seen, <=, 1)
/**
* ASSERT_GT(expected, seen)
@@ -398,7 +398,7 @@
* ASSERT_GT(expected, measured): expected > measured
*/
#define ASSERT_GT(expected, seen) \
- __EXPECT(expected, seen, >, 1)
+ __EXPECT(expected, #expected, seen, #seen, >, 1)
/**
* ASSERT_GE(expected, seen)
@@ -409,7 +409,7 @@
* ASSERT_GE(expected, measured): expected >= measured
*/
#define ASSERT_GE(expected, seen) \
- __EXPECT(expected, seen, >=, 1)
+ __EXPECT(expected, #expected, seen, #seen, >=, 1)
/**
* ASSERT_NULL(seen)
@@ -419,7 +419,7 @@
* ASSERT_NULL(measured): NULL == measured
*/
#define ASSERT_NULL(seen) \
- __EXPECT(NULL, seen, ==, 1)
+ __EXPECT(NULL, "NULL", seen, #seen, ==, 1)
/**
* ASSERT_TRUE(seen)
@@ -429,7 +429,7 @@
* ASSERT_TRUE(measured): measured != 0
*/
#define ASSERT_TRUE(seen) \
- ASSERT_NE(0, seen)
+ __EXPECT(0, "0", seen, #seen, !=, 1)
/**
* ASSERT_FALSE(seen)
@@ -439,7 +439,7 @@
* ASSERT_FALSE(measured): measured == 0
*/
#define ASSERT_FALSE(seen) \
- ASSERT_EQ(0, seen)
+ __EXPECT(0, "0", seen, #seen, ==, 1)
/**
* ASSERT_STREQ(expected, seen)
@@ -472,7 +472,7 @@
* EXPECT_EQ(expected, measured): expected == measured
*/
#define EXPECT_EQ(expected, seen) \
- __EXPECT(expected, seen, ==, 0)
+ __EXPECT(expected, #expected, seen, #seen, ==, 0)
/**
* EXPECT_NE(expected, seen)
@@ -483,7 +483,7 @@
* EXPECT_NE(expected, measured): expected != measured
*/
#define EXPECT_NE(expected, seen) \
- __EXPECT(expected, seen, !=, 0)
+ __EXPECT(expected, #expected, seen, #seen, !=, 0)
/**
* EXPECT_LT(expected, seen)
@@ -494,7 +494,7 @@
* EXPECT_LT(expected, measured): expected < measured
*/
#define EXPECT_LT(expected, seen) \
- __EXPECT(expected, seen, <, 0)
+ __EXPECT(expected, #expected, seen, #seen, <, 0)
/**
* EXPECT_LE(expected, seen)
@@ -505,7 +505,7 @@
* EXPECT_LE(expected, measured): expected <= measured
*/
#define EXPECT_LE(expected, seen) \
- __EXPECT(expected, seen, <=, 0)
+ __EXPECT(expected, #expected, seen, #seen, <=, 0)
/**
* EXPECT_GT(expected, seen)
@@ -516,7 +516,7 @@
* EXPECT_GT(expected, measured): expected > measured
*/
#define EXPECT_GT(expected, seen) \
- __EXPECT(expected, seen, >, 0)
+ __EXPECT(expected, #expected, seen, #seen, >, 0)
/**
* EXPECT_GE(expected, seen)
@@ -527,7 +527,7 @@
* EXPECT_GE(expected, measured): expected >= measured
*/
#define EXPECT_GE(expected, seen) \
- __EXPECT(expected, seen, >=, 0)
+ __EXPECT(expected, #expected, seen, #seen, >=, 0)
/**
* EXPECT_NULL(seen)
@@ -537,7 +537,7 @@
* EXPECT_NULL(measured): NULL == measured
*/
#define EXPECT_NULL(seen) \
- __EXPECT(NULL, seen, ==, 0)
+ __EXPECT(NULL, "NULL", seen, #seen, ==, 0)
/**
* EXPECT_TRUE(seen)
@@ -547,7 +547,7 @@
* EXPECT_TRUE(measured): 0 != measured
*/
#define EXPECT_TRUE(seen) \
- EXPECT_NE(0, seen)
+ __EXPECT(0, "0", seen, #seen, !=, 0)
/**
* EXPECT_FALSE(seen)
@@ -557,7 +557,7 @@
* EXPECT_FALSE(measured): 0 == measured
*/
#define EXPECT_FALSE(seen) \
- EXPECT_EQ(0, seen)
+ __EXPECT(0, "0", seen, #seen, ==, 0)
/**
* EXPECT_STREQ(expected, seen)
@@ -597,7 +597,7 @@
if (_metadata->passed && _metadata->step < 255) \
_metadata->step++;
-#define __EXPECT(_expected, _seen, _t, _assert) do { \
+#define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \
/* Avoid multiple evaluation of the cases */ \
__typeof__(_expected) __exp = (_expected); \
__typeof__(_seen) __seen = (_seen); \
@@ -606,8 +606,8 @@
unsigned long long __exp_print = (uintptr_t)__exp; \
unsigned long long __seen_print = (uintptr_t)__seen; \
__TH_LOG("Expected %s (%llu) %s %s (%llu)", \
- #_expected, __exp_print, #_t, \
- #_seen, __seen_print); \
+ _expected_str, __exp_print, #_t, \
+ _seen_str, __seen_print); \
_metadata->passed = 0; \
/* Ensure the optional handler is triggered */ \
_metadata->trigger = 1; \
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index c9a2abf8be1b..067cb4607d6c 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -5,6 +5,7 @@
* Test code for seccomp bpf.
*/
+#define _GNU_SOURCE
#include <sys/types.h>
/*
@@ -40,10 +41,12 @@
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <sys/times.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
-#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
+#include <poll.h>
#include "../kselftest_harness.h"
@@ -133,6 +136,10 @@ struct seccomp_data {
#define SECCOMP_GET_ACTION_AVAIL 2
#endif
+#ifndef SECCOMP_GET_NOTIF_SIZES
+#define SECCOMP_GET_NOTIF_SIZES 3
+#endif
+
#ifndef SECCOMP_FILTER_FLAG_TSYNC
#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)
#endif
@@ -154,6 +161,44 @@ struct seccomp_metadata {
};
#endif
+#ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER
+#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3)
+
+#define SECCOMP_RET_USER_NOTIF 0x7fc00000U
+
+#define SECCOMP_IOC_MAGIC '!'
+#define SECCOMP_IO(nr) _IO(SECCOMP_IOC_MAGIC, nr)
+#define SECCOMP_IOR(nr, type) _IOR(SECCOMP_IOC_MAGIC, nr, type)
+#define SECCOMP_IOW(nr, type) _IOW(SECCOMP_IOC_MAGIC, nr, type)
+#define SECCOMP_IOWR(nr, type) _IOWR(SECCOMP_IOC_MAGIC, nr, type)
+
+/* Flags for seccomp notification fd ioctl. */
+#define SECCOMP_IOCTL_NOTIF_RECV SECCOMP_IOWR(0, struct seccomp_notif)
+#define SECCOMP_IOCTL_NOTIF_SEND SECCOMP_IOWR(1, \
+ struct seccomp_notif_resp)
+#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOR(2, __u64)
+
+struct seccomp_notif {
+ __u64 id;
+ __u32 pid;
+ __u32 flags;
+ struct seccomp_data data;
+};
+
+struct seccomp_notif_resp {
+ __u64 id;
+ __s64 val;
+ __s32 error;
+ __u32 flags;
+};
+
+struct seccomp_notif_sizes {
+ __u16 seccomp_notif;
+ __u16 seccomp_notif_resp;
+ __u16 seccomp_data;
+};
+#endif
+
#ifndef seccomp
int seccomp(unsigned int op, unsigned int flags, void *args)
{
@@ -2077,7 +2122,8 @@ TEST(detect_seccomp_filter_flags)
{
unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC,
SECCOMP_FILTER_FLAG_LOG,
- SECCOMP_FILTER_FLAG_SPEC_ALLOW };
+ SECCOMP_FILTER_FLAG_SPEC_ALLOW,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER };
unsigned int flag, all_flags;
int i;
long ret;
@@ -2938,6 +2984,403 @@ skip:
ASSERT_EQ(0, kill(pid, SIGKILL));
}
+static int user_trap_syscall(int nr, unsigned int flags)
+{
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
+ offsetof(struct seccomp_data, nr)),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_USER_NOTIF),
+ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
+ };
+
+ struct sock_fprog prog = {
+ .len = (unsigned short)ARRAY_SIZE(filter),
+ .filter = filter,
+ };
+
+ return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog);
+}
+
+#define USER_NOTIF_MAGIC 116983961184613L
+TEST(user_notification_basic)
+{
+ pid_t pid;
+ long ret;
+ int status, listener;
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+ struct pollfd pollfd;
+
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+ };
+ struct sock_fprog prog = {
+ .len = (unsigned short)ARRAY_SIZE(filter),
+ .filter = filter,
+ };
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ /* Check that we get -ENOSYS with no listener attached */
+ if (pid == 0) {
+ if (user_trap_syscall(__NR_getpid, 0) < 0)
+ exit(1);
+ ret = syscall(__NR_getpid);
+ exit(ret >= 0 || errno != ENOSYS);
+ }
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+
+ /* Add some no-op filters so for grins. */
+ EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+ EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+ EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+ EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+
+ /* Check that the basic notification machinery works */
+ listener = user_trap_syscall(__NR_getpid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ EXPECT_GE(listener, 0);
+
+ /* Installing a second listener in the chain should EBUSY */
+ EXPECT_EQ(user_trap_syscall(__NR_getpid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER),
+ -1);
+ EXPECT_EQ(errno, EBUSY);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ ret = syscall(__NR_getpid);
+ exit(ret != USER_NOTIF_MAGIC);
+ }
+
+ pollfd.fd = listener;
+ pollfd.events = POLLIN | POLLOUT;
+
+ EXPECT_GT(poll(&pollfd, 1, -1), 0);
+ EXPECT_EQ(pollfd.revents, POLLIN);
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+
+ pollfd.fd = listener;
+ pollfd.events = POLLIN | POLLOUT;
+
+ EXPECT_GT(poll(&pollfd, 1, -1), 0);
+ EXPECT_EQ(pollfd.revents, POLLOUT);
+
+ EXPECT_EQ(req.data.nr, __NR_getpid);
+
+ resp.id = req.id;
+ resp.error = 0;
+ resp.val = USER_NOTIF_MAGIC;
+
+ /* check that we make sure flags == 0 */
+ resp.flags = 1;
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ resp.flags = 0;
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST(user_notification_kill_in_middle)
+{
+ pid_t pid;
+ long ret;
+ int listener;
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+
+ listener = user_trap_syscall(__NR_getpid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ EXPECT_GE(listener, 0);
+
+ /*
+ * Check that nothing bad happens when we kill the task in the middle
+ * of a syscall.
+ */
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ ret = syscall(__NR_getpid);
+ exit(ret != USER_NOTIF_MAGIC);
+ }
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), 0);
+
+ EXPECT_EQ(kill(pid, SIGKILL), 0);
+ EXPECT_EQ(waitpid(pid, NULL, 0), pid);
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), -1);
+
+ resp.id = req.id;
+ ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
+ EXPECT_EQ(ret, -1);
+ EXPECT_EQ(errno, ENOENT);
+}
+
+static int handled = -1;
+
+static void signal_handler(int signal)
+{
+ if (write(handled, "c", 1) != 1)
+ perror("write from signal");
+}
+
+TEST(user_notification_signal)
+{
+ pid_t pid;
+ long ret;
+ int status, listener, sk_pair[2];
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+ char c;
+
+ ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
+
+ listener = user_trap_syscall(__NR_gettid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ EXPECT_GE(listener, 0);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ close(sk_pair[0]);
+ handled = sk_pair[1];
+ if (signal(SIGUSR1, signal_handler) == SIG_ERR) {
+ perror("signal");
+ exit(1);
+ }
+ /*
+ * ERESTARTSYS behavior is a bit hard to test, because we need
+ * to rely on a signal that has not yet been handled. Let's at
+ * least check that the error code gets propagated through, and
+ * hope that it doesn't break when there is actually a signal :)
+ */
+ ret = syscall(__NR_gettid);
+ exit(!(ret == -1 && errno == 512));
+ }
+
+ close(sk_pair[1]);
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+
+ EXPECT_EQ(kill(pid, SIGUSR1), 0);
+
+ /*
+ * Make sure the signal really is delivered, which means we're not
+ * stuck in the user notification code any more and the notification
+ * should be dead.
+ */
+ EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
+
+ resp.id = req.id;
+ resp.error = -EPERM;
+ resp.val = 0;
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
+ EXPECT_EQ(errno, ENOENT);
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+
+ resp.id = req.id;
+ resp.error = -512; /* -ERESTARTSYS */
+ resp.val = 0;
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST(user_notification_closed_listener)
+{
+ pid_t pid;
+ long ret;
+ int status, listener;
+
+ listener = user_trap_syscall(__NR_getpid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ EXPECT_GE(listener, 0);
+
+ /*
+ * Check that we get an ENOSYS when the listener is closed.
+ */
+ pid = fork();
+ ASSERT_GE(pid, 0);
+ if (pid == 0) {
+ close(listener);
+ ret = syscall(__NR_getpid);
+ exit(ret != -1 && errno != ENOSYS);
+ }
+
+ close(listener);
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+/*
+ * Check that a pid in a child namespace still shows up as valid in ours.
+ */
+TEST(user_notification_child_pid_ns)
+{
+ pid_t pid;
+ int status, listener;
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+
+ ASSERT_EQ(unshare(CLONE_NEWPID), 0);
+
+ listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ ASSERT_GE(listener, 0);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0)
+ exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+ EXPECT_EQ(req.pid, pid);
+
+ resp.id = req.id;
+ resp.error = 0;
+ resp.val = USER_NOTIF_MAGIC;
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+ close(listener);
+}
+
+/*
+ * Check that a pid in a sibling (i.e. unrelated) namespace shows up as 0, i.e.
+ * invalid.
+ */
+TEST(user_notification_sibling_pid_ns)
+{
+ pid_t pid, pid2;
+ int status, listener;
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+
+ listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ ASSERT_GE(listener, 0);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ ASSERT_EQ(unshare(CLONE_NEWPID), 0);
+
+ pid2 = fork();
+ ASSERT_GE(pid2, 0);
+
+ if (pid2 == 0)
+ exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
+
+ EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+ exit(WEXITSTATUS(status));
+ }
+
+ /* Create the sibling ns, and sibling in it. */
+ EXPECT_EQ(unshare(CLONE_NEWPID), 0);
+ EXPECT_EQ(errno, 0);
+
+ pid2 = fork();
+ EXPECT_GE(pid2, 0);
+
+ if (pid2 == 0) {
+ ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+ /*
+ * The pid should be 0, i.e. the task is in some namespace that
+ * we can't "see".
+ */
+ ASSERT_EQ(req.pid, 0);
+
+ resp.id = req.id;
+ resp.error = 0;
+ resp.val = USER_NOTIF_MAGIC;
+
+ ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+ exit(0);
+ }
+
+ close(listener);
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+
+ EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST(user_notification_fault_recv)
+{
+ pid_t pid;
+ int status, listener;
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+
+ listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ ASSERT_GE(listener, 0);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0)
+ exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
+
+ /* Do a bad recv() */
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, NULL), -1);
+ EXPECT_EQ(errno, EFAULT);
+
+ /* We should still be able to receive this notification, though. */
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+ EXPECT_EQ(req.pid, pid);
+
+ resp.id = req.id;
+ resp.error = 0;
+ resp.val = USER_NOTIF_MAGIC;
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST(seccomp_get_notif_sizes)
+{
+ struct seccomp_notif_sizes sizes;
+
+ EXPECT_EQ(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes), 0);
+ EXPECT_EQ(sizes.seccomp_notif, sizeof(struct seccomp_notif));
+ EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp));
+}
+
/*
* TODO:
* - add microbenchmarks
diff --git a/tools/testing/selftests/watchdog/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c
index c6bd9a68306b..c2333c78cf04 100644
--- a/tools/testing/selftests/watchdog/watchdog-test.c
+++ b/tools/testing/selftests/watchdog/watchdog-test.c
@@ -19,7 +19,7 @@
int fd;
const char v = 'V';
-static const char sopts[] = "bdehp:t:Tn:N";
+static const char sopts[] = "bdehp:t:Tn:NL";
static const struct option lopts[] = {
{"bootstatus", no_argument, NULL, 'b'},
{"disable", no_argument, NULL, 'd'},
@@ -30,6 +30,7 @@ static const struct option lopts[] = {
{"gettimeout", no_argument, NULL, 'T'},
{"pretimeout", required_argument, NULL, 'n'},
{"getpretimeout", no_argument, NULL, 'N'},
+ {"gettimeleft", no_argument, NULL, 'L'},
{NULL, no_argument, NULL, 0x0}
};
@@ -77,6 +78,7 @@ static void usage(char *progname)
printf(" -T, --gettimeout Get the timeout\n");
printf(" -n, --pretimeout=T Set the pretimeout to T seconds\n");
printf(" -N, --getpretimeout Get the pretimeout\n");
+ printf(" -L, --gettimeleft Get the time left until timer expires\n");
printf("\n");
printf("Parameters are parsed left-to-right in real-time.\n");
printf("Example: %s -d -t 10 -p 5 -e\n", progname);
@@ -180,6 +182,15 @@ int main(int argc, char *argv[])
else
printf("WDIOC_GETPRETIMEOUT error '%s'\n", strerror(errno));
break;
+ case 'L':
+ oneshot = 1;
+ ret = ioctl(fd, WDIOC_GETTIMELEFT, &flags);
+ if (!ret)
+ printf("WDIOC_GETTIMELEFT returns %u seconds.\n", flags);
+ else
+ printf("WDIOC_GETTIMELEFT error '%s'\n", strerror(errno));
+ break;
+
default:
usage(argv[0]);
goto end;