Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -1911,6 +1911,17 @@ dev/hwpmc/hwpmc_logging.c optional hwpmc dev/hwpmc/hwpmc_mod.c optional hwpmc dev/hwpmc/hwpmc_soft.c optional hwpmc +dev/hwt/hwt.c optional hwt +dev/hwt/hwt_backend.c optional hwt +dev/hwt/hwt_config.c optional hwt +dev/hwt/hwt_context.c optional hwt +dev/hwt/hwt_contexthash.c optional hwt +dev/hwt/hwt_hook.c optional hwt +dev/hwt/hwt_ioctl.c optional hwt +dev/hwt/hwt_owner.c optional hwt +dev/hwt/hwt_ownerhash.c optional hwt +dev/hwt/hwt_record.c optional hwt +dev/hwt/hwt_thread.c optional hwt dev/ichiic/ig4_acpi.c optional ig4 acpi iicbus dev/ichiic/ig4_iic.c optional ig4 iicbus dev/ichiic/ig4_pci.c optional ig4 pci iicbus @@ -3894,6 +3905,7 @@ kern/kern_flag.c standard kern/kern_fork.c standard kern/kern_hhook.c standard +kern/kern_hwt.c standard kern/kern_idle.c standard kern/kern_intr.c standard kern/kern_jail.c standard Index: sys/conf/options =================================================================== --- sys/conf/options +++ sys/conf/options @@ -906,6 +906,9 @@ HWPMC_HOOKS HWPMC_MIPS_BACKTRACE opt_hwpmc_hooks.h +# Hardware Trace (HWT) framework options +HWT_HOOKS + # 802.11 support layer IEEE80211_DEBUG opt_wlan.h IEEE80211_DEBUG_REFCNT opt_wlan.h Index: sys/dev/hwt/hwt.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt.c @@ -0,0 +1,214 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +/* + * Hardware Tracing framework. + * + * The framework manages hardware tracing units that collect information + * about software execution and store it as events in highly compressed format + * into DRAM. The events cover information about control flow changes of a + * program, whether branches taken or not, exceptions taken, timing information, + * cycles elapsed and more. That allows us to restore entire program flow of a + * given application without performance impact. + * + * Design overview. + * + * The framework provides character devices for mmap(2) and ioctl(2) system + * calls to allow user to manage CPU (hardware) tracing units. + * + * /dev/hwt: + * .ioctl: + * hwt_ioctl(): + * a) HWT_IOC_ALLOC + * Allocates kernel tracing context CTX for a given pid. + * b) HWT_IOC_START + * Enables tracing unit for a given context. + * c) HWT_IOC_RECORD_GET + * Transfers (small) record entries collected during program + * execution for a given context to userspace, such as mmaping + * tables of executable and dynamic libraries, interpreter, + * tid of threads created, etc. + * + * /dev/hwt_%d_%d, pid, tid + * .mmap + * Maps tracing buffers to userspace. + * .ioctl + * hwt_thread_ioctl(): + * a) HWT_IOC_BUFPTR_GET + * Transfers current hardware pointer in the filling buffer + * to userspace. + * + * HWT context lifecycle: + * 1. User invokes HWT_IOC_ALLOC ioctl with information about pid to trace and + * size of the buffers for the trace data to allocate. + * Some architectures may have different tracing units supported, so user + * also provides backend name to use for this context, e.g. "coresight". + * 2. Kernel allocates context, lookups the proc for the given pid. Creates + * first hwt_thread in the context and allocates trace buffers for it. + * Immediately, kernel initializes tracing backend. + * 3. User invokes HWT_IOC_START ioctl, kernel marks context as RUNNING. + * At this point any HWT hook invocation by scheduler enables/disables + * tracing for the threads associated with the context (threads of the proc). + * Any new threads creation (of the target proc) procedures will be invoking + * corresponding hooks in HWT framework, so that new hwt_thread and buffers + * allocated, character device for mmap(2) created on the fly. + * 4. User issues HWT_IOC_RECORD_GET ioctl to fetch information about mmaping + * tables and threads created during application startup. + * 5. User mmaps tracing buffers of each thread to userspace (using + * /dev/hwt_%pid_%tid character devices). + * 6. User can repeat 4 if expected thread is not yet created during target + * application execution. + * 7. User issues HWT_IOC_BUFPTR_GET ioctl to get current filling level of the + * hardware buffer of a given thread. + * 8. User invokes trace decoder library to process available data and see the + * results in human readable form. + * 9. User repeates 7 if needed. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define HWT_DEBUG +#undef HWT_DEBUG + +#ifdef HWT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static eventhandler_tag hwt_exit_tag; +static struct cdev *hwt_cdev; +static struct cdevsw hwt_cdevsw = { + .d_version = D_VERSION, + .d_name = "hwt", + .d_mmap_single = NULL, + .d_ioctl = hwt_ioctl +}; + +static void +hwt_process_exit(void *arg __unused, struct proc *p) +{ + struct hwt_owner *ho; + + /* Stop HWTs associated with exiting owner, if any. */ + ho = hwt_ownerhash_lookup(p); + if (ho) + hwt_owner_shutdown(ho); +} + +static int +hwt_load(void) +{ + struct make_dev_args args; + int error; + + make_dev_args_init(&args); + args.mda_devsw = &hwt_cdevsw; + args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; + args.mda_uid = UID_ROOT; + args.mda_gid = GID_WHEEL; + args.mda_mode = 0660; + args.mda_si_drv1 = NULL; + + error = make_dev_s(&args, &hwt_cdev, "hwt"); + if (error != 0) + return (error); + + hwt_backend_load(); + hwt_contexthash_load(); + hwt_ownerhash_load(); + + hwt_exit_tag = EVENTHANDLER_REGISTER(process_exit, hwt_process_exit, + NULL, EVENTHANDLER_PRI_ANY); + + hwt_hook_load(); + + return (0); +} + +static int +hwt_unload(void) +{ + + dprintf("%s\n", __func__); + + /* TODO: deallocate resources. */ + + destroy_dev(hwt_cdev); + + return (0); +} + +static int +hwt_modevent(module_t mod, int type, void *data) +{ + int error; + + switch (type) { + case MOD_LOAD: + error = hwt_load(); + break; + case MOD_UNLOAD: + error = hwt_unload(); + break; + default: + error = 0; + break; + } + + return (error); +} + +static moduledata_t hwt_mod = { + "hwt", + hwt_modevent, + NULL +}; + +DECLARE_MODULE(hwt, hwt_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_VERSION(hwt, 1); Index: sys/dev/hwt/hwt_backend.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_backend.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_BACKEND_H_ +#define _DEV_HWT_HWT_BACKEND_H_ + +struct hwt_backend_ops { + void (*hwt_backend_init)(struct hwt_context *); + void (*hwt_backend_deinit)(void); + void (*hwt_backend_configure)(struct hwt_thread *, int cpu_id); + void (*hwt_backend_enable)(struct hwt_thread *, int cpu_id); + void (*hwt_backend_disable)(struct hwt_thread *, int cpu_id); + int (*hwt_backend_read)(struct hwt_thread *, int cpu_id, + int *curpage, vm_offset_t *curpage_offset); + + /* Debugging only. */ + void (*hwt_backend_dump)(struct hwt_thread *, int cpu_id); +}; + +struct hwt_backend { + const char *name; + struct hwt_backend_ops *ops; + LIST_ENTRY(hwt_backend) next; +}; + +int hwt_backend_init(struct hwt_context *ctx); +int hwt_backend_deinit(struct hwt_context *ctx); +int hwt_backend_configure(struct hwt_thread *thr, int cpu_id); +int hwt_backend_enable(struct hwt_thread *thr, int cpu_id); +int hwt_backend_disable(struct hwt_thread *thr, int cpu_id); +int hwt_backend_dump(struct hwt_thread *thr, int cpu_id); +int hwt_backend_read(struct hwt_thread *thr, int *curpage, + vm_offset_t *curpage_offset); + +int hwt_register(struct hwt_backend *); +struct hwt_backend * hwt_backend_lookup(const char *name); + +void hwt_backend_load(void); + +#define HWT_BACKEND_LOCK() mtx_lock_spin(&hwt_backend_mtx) +#define HWT_BACKEND_UNLOCK() mtx_unlock_spin(&hwt_backend_mtx) + +#endif /* !_DEV_HWT_HWT_BACKEND_H_ */ + Index: sys/dev/hwt/hwt_backend.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_backend.c @@ -0,0 +1,204 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +/* Hardware Trace (HWT) framework. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define HWT_BACKEND_DEBUG +#undef HWT_BACKEND_DEBUG + +#ifdef HWT_BACKEND_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static struct mtx hwt_backend_mtx; +static LIST_HEAD(, hwt_backend) hwt_backends; + +int +hwt_backend_init(struct hwt_context *ctx) +{ + + dprintf("%s\n", __func__); + + ctx->hwt_backend->ops->hwt_backend_init(ctx); + + return (0); +} + +int +hwt_backend_deinit(struct hwt_context *ctx) +{ + + dprintf("%s\n", __func__); + + ctx->hwt_backend->ops->hwt_backend_deinit(); + + return (0); +} + +int +hwt_backend_configure(struct hwt_thread *thr, int cpu_id) +{ + struct hwt_context *ctx; + + dprintf("%s\n", __func__); + + ctx = thr->ctx; + + HWT_THR_ASSERT_LOCKED(thr); + + ctx->hwt_backend->ops->hwt_backend_configure(thr, cpu_id); + + return (0); +} + +int +hwt_backend_enable(struct hwt_thread *thr, int cpu_id) +{ + struct hwt_context *ctx; + + dprintf("%s\n", __func__); + + ctx = thr->ctx; + + HWT_THR_ASSERT_LOCKED(thr); + + ctx->hwt_backend->ops->hwt_backend_enable(thr, cpu_id); + + return (0); +} + +int +hwt_backend_disable(struct hwt_thread *thr, int cpu_id) +{ + struct hwt_context *ctx; + + dprintf("%s\n", __func__); + + ctx = thr->ctx; + + HWT_THR_ASSERT_LOCKED(thr); + + ctx->hwt_backend->ops->hwt_backend_disable(thr, cpu_id); + + return (0); +} + +int __unused +hwt_backend_dump(struct hwt_thread *thr, int cpu_id) +{ + struct hwt_context *ctx; + + dprintf("%s\n", __func__); + + ctx = thr->ctx; + + ctx->hwt_backend->ops->hwt_backend_dump(thr, cpu_id); + + return (0); +} + +int +hwt_backend_read(struct hwt_thread *thr, int *curpage, + vm_offset_t *curpage_offset) +{ + struct hwt_context *ctx; + int error; + + dprintf("%s\n", __func__); + + ctx = thr->ctx; + + error = ctx->hwt_backend->ops->hwt_backend_read(thr, 0, curpage, + curpage_offset); + + return (error); +} + +struct hwt_backend * +hwt_backend_lookup(const char *name) +{ + struct hwt_backend *backend; + + HWT_BACKEND_LOCK(); + LIST_FOREACH(backend, &hwt_backends, next) { + if (strcmp(backend->name, name) == 0) { + HWT_BACKEND_UNLOCK(); + return (backend); + } + } + HWT_BACKEND_UNLOCK(); + + return (NULL); +} + +int +hwt_register(struct hwt_backend *backend) +{ + + if (backend == NULL || + backend->name == NULL || + backend->ops == NULL) + return (EINVAL); + + HWT_BACKEND_LOCK(); + LIST_INSERT_HEAD(&hwt_backends, backend, next); + HWT_BACKEND_UNLOCK(); + + return (0); +} + +void +hwt_backend_load(void) +{ + + mtx_init(&hwt_backend_mtx, "hwt backend", NULL, MTX_SPIN); + LIST_INIT(&hwt_backends); +} Index: sys/dev/hwt/hwt_config.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_config.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_CONFIG_H_ +#define _DEV_HWT_HWT_CONFIG_H_ + +struct hwt_config { +}; + +#endif /* !_DEV_HWT_HWT_CONFIG_H_ */ Index: sys/dev/hwt/hwt_config.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_config.c @@ -0,0 +1,56 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define HWT_CONFIG_DEBUG +#undef HWT_CONFIG_DEBUG + +#ifdef HWT_CONFIG_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static MALLOC_DEFINE(M_HWT_CONFIG, "hwt_config", "HWT config"); Index: sys/dev/hwt/hwt_context.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_context.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_CONTEXT_H_ +#define _DEV_HWT_HWT_CONTEXT_H_ + +struct hwt_context { + LIST_HEAD(, hwt_thread) threads; + LIST_HEAD(, hwt_record_entry) records; + + LIST_ENTRY(hwt_context) next_hch; /* Entry in contexthash. */ + LIST_ENTRY(hwt_context) next_hwts; /* Entry in ho->hwts. */ + + size_t bufsize; /* Trace bufsize for each thr*/ + + struct proc *proc; /* Target proc. */ + pid_t pid; /* Target pid. */ + + void *config; + size_t config_size; + int config_version; + + int pause_on_mmap; + + struct hwt_owner *hwt_owner; + struct hwt_backend *hwt_backend; + int thread_counter; + + struct mtx mtx; + int state; +#define CTX_STATE_RUNNING (1 << 0) +}; + +#define HWT_CTX_LOCK(ctx) mtx_lock_spin(&(ctx)->mtx) +#define HWT_CTX_UNLOCK(ctx) mtx_unlock_spin(&(ctx)->mtx) +#define HWT_CTX_ASSERT_LOCKED(ctx) mtx_assert(&(ctx)->mtx, MA_OWNED) + +struct hwt_context * hwt_ctx_alloc(void); +void hwt_ctx_free(struct hwt_context *ctx); + +#endif /* !_DEV_HWT_HWT_CONTEXT_H_ */ Index: sys/dev/hwt/hwt_context.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_context.c @@ -0,0 +1,81 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define HWT_DEBUG +#undef HWT_DEBUG + +#ifdef HWT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static MALLOC_DEFINE(M_HWT_CTX, "hwt_ctx", "Hardware Trace"); + +struct hwt_context * +hwt_ctx_alloc(void) +{ + struct hwt_context *ctx; + + ctx = malloc(sizeof(struct hwt_context), M_HWT_CTX, M_WAITOK | M_ZERO); + ctx->thread_counter = 1; + + LIST_INIT(&ctx->records); + LIST_INIT(&ctx->threads); + mtx_init(&ctx->mtx, "ctx", NULL, MTX_SPIN); + + return (ctx); +} + +void +hwt_ctx_free(struct hwt_context *ctx) +{ + + free(ctx, M_HWT_CTX); +} Index: sys/dev/hwt/hwt_contexthash.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_contexthash.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_CONTEXTHASH_H_ +#define _DEV_HWT_HWT_CONTEXTHASH_H_ + +struct hwt_context * hwt_contexthash_lookup(struct proc *p); +void hwt_contexthash_insert(struct hwt_context *ctx); +void hwt_contexthash_remove(struct hwt_context *ctx); +void hwt_contexthash_load(void); + +#define HWT_CTXHASH_LOCK() mtx_lock_spin(&hwt_contexthash_mtx) +#define HWT_CTXHASH_UNLOCK() mtx_unlock_spin(&hwt_contexthash_mtx) + +#endif /* !_DEV_HWT_HWT_CONTEXTHASH_H_ */ Index: sys/dev/hwt/hwt_contexthash.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_contexthash.c @@ -0,0 +1,133 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define HWT_DEBUG +#undef HWT_DEBUG + +#ifdef HWT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +#define HWT_CONTEXTHASH_SIZE 1024 + +static MALLOC_DEFINE(M_HWT_CONTEXTHASH, "hwt_chash", "Hardware Trace"); + +/* + * Hash function. Discard the lower 2 bits of the pointer since + * these are always zero for our uses. The hash multiplier is + * round((2^LONG_BIT) * ((sqrt(5)-1)/2)). + */ + +#define _HWT_HM 11400714819323198486u /* hash multiplier */ +#define HWT_HASH_PTR(P, M) ((((unsigned long) (P) >> 2) * _HWT_HM) & (M)) + +static struct mtx hwt_contexthash_mtx; +static u_long hwt_contexthashmask; +static LIST_HEAD(hwt_contexthash, hwt_context) *hwt_contexthash; + +/* + * To use by hwt_switch_in/out() and hwt_record() only. + * This function returns mtx locked. + */ +struct hwt_context * +hwt_contexthash_lookup(struct proc *p) +{ + struct hwt_contexthash *hch; + struct hwt_context *ctx; + int hindex; + + hindex = HWT_HASH_PTR(p, hwt_contexthashmask); + hch = &hwt_contexthash[hindex]; + + HWT_CTXHASH_LOCK(); + LIST_FOREACH(ctx, hch, next_hch) { + if (ctx->proc == p) { + HWT_CTX_LOCK(ctx); + HWT_CTXHASH_UNLOCK(); + return (ctx); + } + } + HWT_CTXHASH_UNLOCK(); + + return (NULL); +} + +void +hwt_contexthash_insert(struct hwt_context *ctx) +{ + struct hwt_contexthash *hch; + int hindex; + + PROC_LOCK_ASSERT(ctx->proc, MA_OWNED); + + hindex = HWT_HASH_PTR(ctx->proc, hwt_contexthashmask); + hch = &hwt_contexthash[hindex]; + + HWT_CTXHASH_LOCK(); + LIST_INSERT_HEAD(hch, ctx, next_hch); + HWT_CTXHASH_UNLOCK(); +} + +void +hwt_contexthash_remove(struct hwt_context *ctx) +{ + + HWT_CTXHASH_LOCK(); + LIST_REMOVE(ctx, next_hch); + HWT_CTXHASH_UNLOCK(); +} + +void +hwt_contexthash_load(void) +{ + + hwt_contexthash = hashinit(HWT_CONTEXTHASH_SIZE, M_HWT_CONTEXTHASH, + &hwt_contexthashmask); + mtx_init(&hwt_contexthash_mtx, "hwt ctx hash", "hwt ctx", MTX_SPIN); +} Index: sys/dev/hwt/hwt_hook.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_hook.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#include + +#ifndef _DEV_HWT_HWT_HOOK_H_ +#define _DEV_HWT_HWT_HOOK_H_ + +#define HWT_SWITCH_IN 0 +#define HWT_SWITCH_OUT 1 +#define HWT_THREAD_EXIT 2 +#define HWT_THREAD_CREATE 3 +#define HWT_THREAD_SET_NAME 4 +#define HWT_RECORD 5 +#define HWT_MMAP 6 +#define HWT_EXEC 7 + +#define HWT_CALL_HOOK(td, func, arg) \ +do { \ + if (hwt_hook != NULL) \ + (hwt_hook)((td), (func), (arg)); \ +} while (0) + +extern void (*hwt_hook)(struct thread *td, int func, void *arg); + +void hwt_hook_load(void); +void hwt_hook_unload(void); + +#endif /* !_DEV_HWT_HWT_HOOK_H_ */ Index: sys/dev/hwt/hwt_hook.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_hook.c @@ -0,0 +1,247 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +/* Hardware Trace (HWT) framework. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWT_DEBUG +#undef HWT_DEBUG + +#ifdef HWT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static void +hwt_switch_in(struct thread *td) +{ + struct hwt_context *ctx; + struct hwt_thread *thr; + struct proc *p; + int cpu_id; + + p = td->td_proc; + + cpu_id = PCPU_GET(cpuid); + + ctx = hwt_contexthash_lookup(p); + if (ctx == NULL) + return; + + if (ctx->state != CTX_STATE_RUNNING) { + HWT_CTX_UNLOCK(ctx); + return; + } + + thr = hwt_thread_lookup(ctx, td); + + printf("%s: thr %p index %d tid %d on cpu_id %d\n", __func__, thr, + thr->thread_id, td->td_tid, cpu_id); + + hwt_backend_configure(thr, cpu_id); + hwt_backend_enable(thr, cpu_id); + + HWT_THR_UNLOCK(thr); +} + +static void +hwt_switch_out(struct thread *td) +{ + struct hwt_context *ctx; + struct hwt_thread *thr; + struct proc *p; + int cpu_id; + + p = td->td_proc; + + cpu_id = PCPU_GET(cpuid); + + ctx = hwt_contexthash_lookup(p); + if (ctx == NULL) + return; + + if (ctx->state != CTX_STATE_RUNNING) { + HWT_CTX_UNLOCK(ctx); + return; + } + thr = hwt_thread_lookup(ctx, td); + + printf("%s: thr %p index %d tid %d on cpu_id %d\n", __func__, thr, + thr->thread_id, td->td_tid, cpu_id); + + hwt_backend_disable(thr, cpu_id); + HWT_THR_UNLOCK(thr); +} + +static void +hwt_thread_exit(struct thread *td) +{ + struct hwt_context *ctx; + struct hwt_thread *thr; + struct proc *p; + int cpu_id; + + p = td->td_proc; + + cpu_id = PCPU_GET(cpuid); + + ctx = hwt_contexthash_lookup(p); + if (ctx == NULL) + return; + + if (ctx->state != CTX_STATE_RUNNING) { + HWT_CTX_UNLOCK(ctx); + return; + } + thr = hwt_thread_lookup(ctx, td); + + thr->state = HWT_THREAD_STATE_EXITED; + + printf("%s: thr %p index %d tid %d on cpu_id %d\n", __func__, thr, + thr->thread_id, td->td_tid, cpu_id); + + hwt_backend_disable(thr, cpu_id); + HWT_THR_UNLOCK(thr); +} + +static void +hwt_hook_mmap(struct thread *td) +{ + struct hwt_context *ctx; + struct hwt_thread *thr; + struct proc *p; + int pause; + + p = td->td_proc; + + ctx = hwt_contexthash_lookup(p); + if (ctx == NULL) + return; + + /* The ctx state could be any here. */ + + pause = ctx->pause_on_mmap ? 1 : 0; + + thr = hwt_thread_lookup(ctx, td); + + /* + * msleep(9) atomically releases the mtx lock, so take refcount + * to ensure that thr is not destroyed. + */ + refcount_acquire(&thr->refcnt); + + if (pause) + msleep_spin(thr, &thr->mtx, "hwt-mmap", 0); + + HWT_THR_UNLOCK(thr); + + if (refcount_release(&thr->refcnt)) + hwt_thread_free(thr); +} + +static void +hwt_hook_handler(struct thread *td, int func, void *arg) +{ + struct hwt_thread *thr; + struct proc *p; + int error; + + p = td->td_proc; + if ((p->p_flag2 & P2_HWT) == 0) + return; + + switch (func) { + case HWT_SWITCH_IN: + hwt_switch_in(td); + break; + case HWT_SWITCH_OUT: + hwt_switch_out(td); + break; + case HWT_THREAD_CREATE: + error = hwt_thread_create(td, &thr); + if (error == 0) + hwt_record_thread(thr); + break; + case HWT_THREAD_SET_NAME: + /* TODO. */ + break; + case HWT_THREAD_EXIT: + hwt_thread_exit(td); + break; + case HWT_EXEC: + hwt_record(td, arg); + hwt_hook_mmap(td); + break; + case HWT_MMAP: + hwt_record(td, arg); + hwt_hook_mmap(td); + break; + case HWT_RECORD: + hwt_record(td, arg); + break; + }; +} + +void +hwt_hook_load(void) +{ + + hwt_hook = hwt_hook_handler; +} + +void +hwt_hook_unload(void) +{ + + hwt_hook = NULL; +} Index: sys/dev/hwt/hwt_ioctl.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_ioctl.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_IOCTL_H +#define _DEV_HWT_HWT_IOCTL_H + +int hwt_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, + struct thread *td); + +#endif /* !_DEV_HWT_HWT_IOCTL_H */ Index: sys/dev/hwt/hwt_ioctl.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_ioctl.c @@ -0,0 +1,400 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +/* Hardware Trace (HWT) framework. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWT_IOCTL_DEBUG +#undef HWT_IOCTL_DEBUG + +#ifdef HWT_IOCTL_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +/* No real reason for these limitations just sanity checks. */ +#define HWT_MAXBUFSIZE (32UL * 1024 * 1024 * 1024) /* 32 GB */ +#define HWT_MAXCONFIGSIZE 1024 + +static MALLOC_DEFINE(M_HWT_IOCTL, "hwt_ioctl", "Hardware Trace"); + +/* + * Check if owner process *o can trace target process *t. + */ + +static int +hwt_priv_check(struct proc *o, struct proc *t) +{ + struct ucred *oc, *tc; + int error; + int i; + + PROC_LOCK(o); + oc = o->p_ucred; + crhold(oc); + PROC_UNLOCK(o); + + PROC_LOCK_ASSERT(t, MA_OWNED); + tc = t->p_ucred; + crhold(tc); + + error = 0; + + /* + * The effective uid of the HWT owner should match at least one + * of the effective / real / saved uids of the target process. + */ + + if (oc->cr_uid != tc->cr_uid && + oc->cr_uid != tc->cr_svuid && + oc->cr_uid != tc->cr_ruid) { + error = EPERM; + goto done; + } + + /* + * Everyone of the target's group ids must be in the owner's + * group list. + */ + for (i = 0; i < tc->cr_ngroups; i++) + if (!groupmember(tc->cr_groups[i], oc)) { + error = EPERM; + goto done; + } + + /* Check the read and saved GIDs too. */ + if (!groupmember(tc->cr_rgid, oc) || + !groupmember(tc->cr_svgid, oc)) { + error = EPERM; + goto done; + } + +done: + crfree(tc); + crfree(oc); + + return (error); +} + +static int +hwt_ioctl_send_records(struct hwt_context *ctx, + struct hwt_record_get *record_get) +{ + struct hwt_record_user_entry *user_entry; + int nitems_req; + int error; + int i; + + nitems_req = 0; + + error = copyin(record_get->nentries, &nitems_req, sizeof(int)); + if (error) + return (error); + + if (nitems_req < 1 || nitems_req > 1024) + return (ENXIO); + + user_entry = malloc(sizeof(struct hwt_record_user_entry) * nitems_req, + M_HWT_IOCTL, M_WAITOK | M_ZERO); + + i = hwt_record_grab(ctx, user_entry, nitems_req); + if (i > 0) + error = copyout(user_entry, record_get->records, + sizeof(struct hwt_record_user_entry) * i); + + if (error == 0) + error = copyout(&i, record_get->nentries, sizeof(int)); + + free(user_entry, M_HWT_IOCTL); + + return (error); +} + +static int +hwt_ioctl_alloc(struct thread *td, struct hwt_alloc *halloc) +{ + char backend_name[HWT_BACKEND_MAXNAMELEN]; + struct hwt_backend *backend; + struct hwt_context *ctx; + struct hwt_thread *thr; + struct hwt_owner *ho; + struct proc *p; + int error; + + if (halloc->bufsize > HWT_MAXBUFSIZE) + return (EINVAL); + if (halloc->bufsize % PAGE_SIZE) + return (EINVAL); + if (halloc->backend_name == NULL) + return (EINVAL); + + error = copyinstr(halloc->backend_name, (void *)backend_name, + HWT_BACKEND_MAXNAMELEN, NULL); + if (error) + return (error); + + backend = hwt_backend_lookup(backend_name); + if (backend == NULL) + return (ENXIO); + + /* First get the owner. */ + ho = hwt_ownerhash_lookup(td->td_proc); + if (ho) { + /* Check if the owner have this pid configured already. */ + ctx = hwt_owner_lookup_ctx(ho, halloc->pid); + if (ctx) + return (EEXIST); + } else { + /* Create a new owner. */ + ho = hwt_owner_alloc(td->td_proc); + if (ho == NULL) + return (ENOMEM); + hwt_ownerhash_insert(ho); + } + + /* Allocate a new HWT context. */ + ctx = hwt_ctx_alloc(); + ctx->bufsize = halloc->bufsize; + ctx->pid = halloc->pid; + ctx->hwt_backend = backend; + ctx->hwt_owner = ho; + + /* Allocate first thread and buffers. */ + error = hwt_thread_alloc(&thr, ctx->bufsize); + if (error) { + hwt_ctx_free(ctx); + return (error); + } + + /* Since we done with malloc, now get the victim proc. */ + p = pfind(halloc->pid); + if (p == NULL) { + hwt_thread_free(thr); + hwt_ctx_free(ctx); + return (ENXIO); + } + + /* Ensure we can trace it. */ + error = hwt_priv_check(td->td_proc, p); + if (error) { + hwt_thread_free(thr); + hwt_ctx_free(ctx); + PROC_UNLOCK(p); + return (error); + } + + /* All good. */ + thr->ctx = ctx; + thr->tid = FIRST_THREAD_IN_PROC(p)->td_tid; + thr->thread_id = atomic_fetchadd_int(&ctx->thread_counter, 1); + + HWT_CTX_LOCK(ctx); + hwt_thread_insert(ctx, thr); + HWT_CTX_UNLOCK(ctx); + + /* hwt_owner_insert_ctx? */ + mtx_lock(&ho->mtx); + LIST_INSERT_HEAD(&ho->hwts, ctx, next_hwts); + mtx_unlock(&ho->mtx); + + p->p_flag2 |= P2_HWT; + + ctx->proc = p; + hwt_contexthash_insert(ctx); + PROC_UNLOCK(p); + + error = hwt_backend_init(ctx); + if (error) { + /* TODO: deallocate resources. */ + return (error); + } + + error = hwt_thread_create_cdev(thr, ctx->pid); + if (error) { + /* TODO: deallocate resources. */ + return (error); + } + + /* Pass thread ID to user for mmap. */ + hwt_record_thread(thr); + + return (0); +} + +static int +hwt_ioctl_set_config(struct thread *td, struct hwt_context *ctx, + struct hwt_set_config *sconf) +{ + size_t config_size; + void *old_config; + void *config; + int error; + + config_size = sconf->config_size; + if (config_size == 0) + return (0); + + if (config_size > HWT_MAXCONFIGSIZE) + return (EFBIG); + + config = malloc(config_size, M_HWT_IOCTL, M_WAITOK | M_ZERO); + + error = copyin(sconf->config, config, config_size); + if (error) { + free(config, M_HWT_IOCTL); + return (error); + } + + HWT_CTX_LOCK(ctx); + old_config = ctx->config; + ctx->config = config; + ctx->config_size = sconf->config_size; + ctx->config_version = sconf->config_version; + HWT_CTX_UNLOCK(ctx); + + if (old_config != NULL) + free(old_config, M_HWT_IOCTL); + + return (error); +} + +int +hwt_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, + struct thread *td) +{ + struct hwt_record_get *rget; + struct hwt_set_config *sconf; + struct hwt_context *ctx; + struct hwt_owner *ho; + struct hwt_start *s; + struct hwt_wakeup *hwakeup; + struct hwt_thread *thr; + int error; + + /* Check if process is registered owner of any HWTs. */ + ho = hwt_ownerhash_lookup(td->td_proc); + if (ho == NULL && cmd != HWT_IOC_ALLOC) + return (ENXIO); + + switch (cmd) { + case HWT_IOC_ALLOC: + /* Allocate HWT context. */ + error = hwt_ioctl_alloc(td, (struct hwt_alloc *)addr); + return (error); + + case HWT_IOC_START: + /* Start tracing. */ + s = (struct hwt_start *)addr; + dprintf("%s: start, pid %d\n", __func__, s->pid); + ctx = hwt_owner_lookup_ctx(ho, s->pid); + if (ctx == NULL) + return (ENXIO); + + HWT_CTX_LOCK(ctx); + if (ctx->state == CTX_STATE_RUNNING) { + /* Already running ? */ + HWT_CTX_UNLOCK(ctx); + return (ENXIO); + } + ctx->state = CTX_STATE_RUNNING; + HWT_CTX_UNLOCK(ctx); + + return (0); + + case HWT_IOC_RECORD_GET: + rget = (struct hwt_record_get *)addr; + ctx = hwt_owner_lookup_ctx(ho, rget->pid); + if (ctx == NULL) + return (ENXIO); + + error = hwt_ioctl_send_records(ctx, rget); + return (error); + + case HWT_IOC_SET_CONFIG: + sconf = (struct hwt_set_config *)addr; + ctx = hwt_owner_lookup_ctx(ho, sconf->pid); + if (ctx == NULL) + return (ENXIO); + + error = hwt_ioctl_set_config(td, ctx, sconf); + if (error) + return (error); + + ctx->pause_on_mmap = sconf->pause_on_mmap ? 1 : 0; + + return (0); + case HWT_IOC_WAKEUP: + hwakeup = (struct hwt_wakeup *)addr; + ctx = hwt_owner_lookup_ctx(ho, hwakeup->pid); + if (ctx == NULL) + return (ENXIO); + + HWT_CTX_LOCK(ctx); + thr = hwt_thread_lookup_by_tid(ctx, hwakeup->tid); + if (thr) + HWT_THR_LOCK(thr); + HWT_CTX_UNLOCK(ctx); + + if (thr == NULL) + return (ENOENT); + + wakeup(thr); + + HWT_THR_UNLOCK(thr); + + return (0); + default: + return (ENXIO); + }; +} Index: sys/dev/hwt/hwt_owner.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_owner.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_OWNER_H_ +#define _DEV_HWT_HWT_OWNER_H_ + +struct hwt_owner { + struct proc *p; + struct mtx mtx; /* Protects hwts. */ + LIST_HEAD(, hwt_context) hwts; /* Owned HWTs. */ + LIST_ENTRY(hwt_owner) next; /* Entry in hwt owner hash. */ +}; + + +struct hwt_context * hwt_owner_lookup_ctx(struct hwt_owner *ho, pid_t pid); +struct hwt_owner * hwt_owner_alloc(struct proc *p); +void hwt_owner_free(struct hwt_owner *ho); +void hwt_owner_shutdown(struct hwt_owner *ho); + +#endif /* !_DEV_HWT_HWT_OWNER_H_ */ Index: sys/dev/hwt/hwt_owner.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_owner.c @@ -0,0 +1,170 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWT_DEBUG +#undef HWT_DEBUG + +#ifdef HWT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static MALLOC_DEFINE(M_HWT_OWNER, "hwt_owner", "Hardware Trace"); + +struct hwt_context * +hwt_owner_lookup_ctx(struct hwt_owner *ho, pid_t pid) +{ + struct hwt_context *ctx; + + mtx_lock(&ho->mtx); + LIST_FOREACH(ctx, &ho->hwts, next_hwts) { + if (ctx->pid == pid) { + mtx_unlock(&ho->mtx); + return (ctx); + } + } + mtx_unlock(&ho->mtx); + + return (NULL); +} + +struct hwt_owner * +hwt_owner_alloc(struct proc *p) +{ + struct hwt_owner *ho; + + ho = malloc(sizeof(struct hwt_owner), M_HWT_OWNER, + M_WAITOK | M_ZERO); + ho->p = p; + + LIST_INIT(&ho->hwts); + mtx_init(&ho->mtx, "hwts", NULL, MTX_DEF); + + return (ho); +} + +void +hwt_owner_free(struct hwt_owner *ho) +{ + + free(ho, M_HWT_OWNER); +} + +void +hwt_owner_shutdown(struct hwt_owner *ho) +{ + struct hwt_context *ctx; + struct hwt_thread *thr; + + printf("%s: stopping hwt owner\n", __func__); + + while (1) { + mtx_lock(&ho->mtx); + ctx = LIST_FIRST(&ho->hwts); + if (ctx) + LIST_REMOVE(ctx, next_hwts); + mtx_unlock(&ho->mtx); + + if (ctx == NULL) + break; + + hwt_contexthash_remove(ctx); + + /* + * It could be that hwt_switch_in/out() or hwt_record() have + * this ctx locked right here. + * if not, change state immediately, so they give up. + */ + + HWT_CTX_LOCK(ctx); + ctx->state = 0; + HWT_CTX_UNLOCK(ctx); + + /* hwt_switch_in() is now completed. */ + + hwt_backend_deinit(ctx); + + /* Remove thread first. */ + + dprintf("%s: remove threads\n", __func__); + + while (1) { + HWT_CTX_LOCK(ctx); + thr = LIST_FIRST(&ctx->threads); + if (thr) { + LIST_REMOVE(thr, next); + HWT_THR_LOCK(thr); + } + HWT_CTX_UNLOCK(ctx); + + if (thr == NULL) + break; + + wakeup(thr); + + HWT_THR_UNLOCK(thr); + + /* TODO: move into hwt_thread_free? */ + destroy_dev_sched(thr->cdev); + + if (refcount_release(&thr->refcnt)) + hwt_thread_free(thr); + } + + hwt_ctx_free(ctx); + } + + hwt_ownerhash_remove(ho); + hwt_owner_free(ho); +} Index: sys/dev/hwt/hwt_ownerhash.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_ownerhash.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_OWNERHASH_H_ +#define _DEV_HWT_HWT_OWNERHASH_H_ + +struct hwt_owner * hwt_ownerhash_lookup(struct proc *p); +void hwt_ownerhash_insert(struct hwt_owner *ho); +void hwt_ownerhash_remove(struct hwt_owner *ho); +void hwt_ownerhash_load(void); + +#define HWT_OWNERHASH_LOCK() mtx_lock_spin(&hwt_ownerhash_mtx) +#define HWT_OWNERHASH_UNLOCK() mtx_unlock_spin(&hwt_ownerhash_mtx) + +#endif /* !_DEV_HWT_HWT_OWNERHASH_H_ */ Index: sys/dev/hwt/hwt_ownerhash.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_ownerhash.c @@ -0,0 +1,126 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define HWT_DEBUG +#undef HWT_DEBUG + +#ifdef HWT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +#define HWT_OWNERHASH_SIZE 1024 + +static MALLOC_DEFINE(M_HWT_OWNERHASH, "hwt_ohash", "Hardware Trace"); + +/* + * Hash function. Discard the lower 2 bits of the pointer since + * these are always zero for our uses. The hash multiplier is + * round((2^LONG_BIT) * ((sqrt(5)-1)/2)). + */ + +#define _HWT_HM 11400714819323198486u /* hash multiplier */ +#define HWT_HASH_PTR(P, M) ((((unsigned long) (P) >> 2) * _HWT_HM) & (M)) + +static struct mtx hwt_ownerhash_mtx; +static u_long hwt_ownerhashmask; +static LIST_HEAD(hwt_ownerhash, hwt_owner) *hwt_ownerhash; + +struct hwt_owner * +hwt_ownerhash_lookup(struct proc *p) +{ + struct hwt_ownerhash *hoh; + struct hwt_owner *ho; + int hindex; + + hindex = HWT_HASH_PTR(p, hwt_ownerhashmask); + hoh = &hwt_ownerhash[hindex]; + + HWT_OWNERHASH_LOCK(); + LIST_FOREACH(ho, hoh, next) { + if (ho->p == p) { + HWT_OWNERHASH_UNLOCK(); + return (ho); + } + } + HWT_OWNERHASH_UNLOCK(); + + return (NULL); +} + +void +hwt_ownerhash_insert(struct hwt_owner *ho) +{ + struct hwt_ownerhash *hoh; + int hindex; + + hindex = HWT_HASH_PTR(ho->p, hwt_ownerhashmask); + hoh = &hwt_ownerhash[hindex]; + + HWT_OWNERHASH_LOCK(); + LIST_INSERT_HEAD(hoh, ho, next); + HWT_OWNERHASH_UNLOCK(); +} + +void +hwt_ownerhash_remove(struct hwt_owner *ho) +{ + + /* Destroy hwt owner. */ + HWT_OWNERHASH_LOCK(); + LIST_REMOVE(ho, next); + HWT_OWNERHASH_UNLOCK(); +} + +void +hwt_ownerhash_load(void) +{ + + hwt_ownerhash = hashinit(HWT_OWNERHASH_SIZE, M_HWT_OWNERHASH, + &hwt_ownerhashmask); + mtx_init(&hwt_ownerhash_mtx, "hwt-owner-hash", "hwt-owner", MTX_SPIN); +} Index: sys/dev/hwt/hwt_record.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_record.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_RECORD_H_ +#define _DEV_HWT_HWT_RECORD_H_ + +int hwt_record_grab(struct hwt_context *ctx, + struct hwt_record_user_entry *user_entry, int nitems_req); +void hwt_record_thread(struct hwt_thread *thr); +void hwt_record(struct thread *td, struct hwt_record_entry *ent); + +#endif /* !_DEV_HWT_HWT_RECORD_H_ */ Index: sys/dev/hwt/hwt_record.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_record.c @@ -0,0 +1,135 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define HWT_RECORD_DEBUG +#undef HWT_RECORD_DEBUG + +#ifdef HWT_RECORD_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static MALLOC_DEFINE(M_HWT_RECORD, "hwt_record", "Hardware Trace"); + +void +hwt_record(struct thread *td, struct hwt_record_entry *ent) +{ + struct hwt_record_entry *entry; + struct hwt_context *ctx; + struct proc *p; + + p = td->td_proc; + + KASSERT(ent != NULL, ("ent is NULL")); + KASSERT(ent->fullpath != NULL, ("fullpath is NULL")); + + entry = malloc(sizeof(struct hwt_record_entry), M_HWT_RECORD, M_WAITOK); + entry->record_type = ent->record_type; + entry->tid = td->td_tid; + entry->fullpath = strdup(ent->fullpath, M_HWT_RECORD); + entry->addr = ent->addr; + entry->size = ent->size; + + ctx = hwt_contexthash_lookup(p); + if (ctx == NULL) { + /* TODO: release resources. */ + return; + } + LIST_INSERT_HEAD(&ctx->records, entry, next); + HWT_CTX_UNLOCK(ctx); +} + +void +hwt_record_thread(struct hwt_thread *thr) +{ + struct hwt_record_entry *entry; + struct hwt_context *ctx; + + ctx = thr->ctx; + + entry = malloc(sizeof(struct hwt_record_entry), M_HWT_RECORD, + M_WAITOK | M_ZERO); + entry->record_type = HWT_RECORD_THREAD_CREATE; + entry->tid = thr->tid; + + HWT_CTX_LOCK(ctx); + LIST_INSERT_HEAD(&ctx->records, entry, next); + HWT_CTX_UNLOCK(ctx); +} + +int +hwt_record_grab(struct hwt_context *ctx, + struct hwt_record_user_entry *user_entry, int nitems_req) +{ + struct hwt_record_entry *entry; + int i; + + for (i = 0; i < nitems_req; i++) { + HWT_CTX_LOCK(ctx); + entry = LIST_FIRST(&ctx->records); + if (entry) + LIST_REMOVE(entry, next); + HWT_CTX_UNLOCK(ctx); + + if (entry == NULL) + break; + + user_entry[i].addr = entry->addr; + user_entry[i].size = entry->size; + user_entry[i].record_type = entry->record_type; + user_entry[i].tid = entry->tid; + if (entry->fullpath != NULL) { + strncpy(user_entry[i].fullpath, entry->fullpath, + MAXPATHLEN); + free(entry->fullpath, M_HWT_RECORD); + } + + free(entry, M_HWT_RECORD); + } + + return (i); +} Index: sys/dev/hwt/hwt_thread.h =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_thread.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_HWT_HWT_THREAD_H_ +#define _DEV_HWT_HWT_THREAD_H_ + +struct hwt_thread { + vm_page_t *pages; + int npages; + lwpid_t tid; + vm_object_t obj; + struct cdev *cdev; + struct hwt_context *ctx; + LIST_ENTRY(hwt_thread) next; + int thread_id; /* Specific to ARM backend.*/ + int state; +#define HWT_THREAD_STATE_EXITED (1 << 0) + struct mtx mtx; + u_int refcnt; +}; + +/* Thread allocation. */ +int hwt_thread_alloc(struct hwt_thread **thr0, size_t bufsize); +int hwt_thread_create_cdev(struct hwt_thread *thr, pid_t pid); +int hwt_thread_create(struct thread *td, struct hwt_thread **thr0); + +/* Thread de-allocation. */ +void hwt_thread_free(struct hwt_thread *thr); +void hwt_thread_destroy_buffers(struct hwt_thread *thr); + +/* Thread list mgt. */ +void hwt_thread_insert(struct hwt_context *ctx, struct hwt_thread *thr); +struct hwt_thread * hwt_thread_first(struct hwt_context *ctx); +struct hwt_thread * hwt_thread_lookup(struct hwt_context *ctx, + struct thread *td); +struct hwt_thread * hwt_thread_lookup_by_tid(struct hwt_context *ctx, + lwpid_t tid); + +#define HWT_THR_LOCK(thr) mtx_lock_spin(&(thr)->mtx) +#define HWT_THR_UNLOCK(thr) mtx_unlock_spin(&(thr)->mtx) +#define HWT_THR_ASSERT_LOCKED(thr) mtx_assert(&(thr)->mtx, MA_OWNED) + +#endif /* !_DEV_HWT_HWT_THREAD_H_ */ Index: sys/dev/hwt/hwt_thread.c =================================================================== --- /dev/null +++ sys/dev/hwt/hwt_thread.c @@ -0,0 +1,456 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWT_THREAD_DEBUG +#undef HWT_THREAD_DEBUG + +#ifdef HWT_THREAD_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +static MALLOC_DEFINE(M_HWT_THREAD, "hwt_thread", "Hardware Trace"); + +static int +hwt_thread_fault(vm_object_t vm_obj, vm_ooffset_t offset, + int prot, vm_page_t *mres) +{ + + return (0); +} + +static int +hwt_thread_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, + vm_ooffset_t foff, struct ucred *cred, u_short *color) +{ + + *color = 0; + + return (0); +} + +static void +hwt_thread_dtor(void *handle) +{ + +} + +static struct cdev_pager_ops hwt_thread_pager_ops = { + .cdev_pg_fault = hwt_thread_fault, + .cdev_pg_ctor = hwt_thread_ctor, + .cdev_pg_dtor = hwt_thread_dtor +}; + +struct hwt_thread * +hwt_thread_first(struct hwt_context *ctx) +{ + struct hwt_thread *thr; + + HWT_CTX_ASSERT_LOCKED(ctx); + + thr = LIST_FIRST(&ctx->threads); + + KASSERT(thr != NULL, ("thr is NULL")); + + return (thr); +} + +static int +hwt_thread_alloc_pages(struct hwt_thread *thr) +{ + vm_paddr_t low, high, boundary; + vm_memattr_t memattr; + vm_pointer_t va; + int alignment; + vm_page_t m; + int pflags; + int tries; + int i; + + alignment = PAGE_SIZE; + low = 0; + high = -1UL; + boundary = 0; + pflags = VM_ALLOC_NORMAL | VM_ALLOC_NOBUSY | VM_ALLOC_WIRED | + VM_ALLOC_ZERO; + memattr = VM_MEMATTR_DEVICE; + + thr->obj = cdev_pager_allocate(thr, OBJT_MGTDEVICE, + &hwt_thread_pager_ops, thr->npages * PAGE_SIZE, PROT_READ, 0, + curthread->td_ucred); + + for (i = 0; i < thr->npages; i++) { + tries = 0; +retry: + m = vm_page_alloc_noobj_contig(pflags, 1, low, high, + alignment, boundary, memattr); + if (m == NULL) { + if (tries < 3) { + if (!vm_page_reclaim_contig(pflags, 1, low, + high, alignment, boundary)) + vm_wait(NULL); + tries++; + goto retry; + } + + return (ENOMEM); + } + +#if 0 + if ((m->flags & PG_ZERO) == 0) + pmap_zero_page(m); +#endif + + va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)); + cpu_dcache_wb_range(va, PAGE_SIZE); + + m->valid = VM_PAGE_BITS_ALL; + m->oflags &= ~VPO_UNMANAGED; + m->flags |= PG_FICTITIOUS; + thr->pages[i] = m; + + VM_OBJECT_WLOCK(thr->obj); + vm_page_insert(m, thr->obj, i); + VM_OBJECT_WUNLOCK(thr->obj); + } + + return (0); +} + +static int +hwt_thread_open(struct cdev *cdev, int oflags, int devtype, struct thread *td) +{ + + dprintf("%s\n", __func__); + + return (0); +} + +static int +hwt_thread_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, + vm_size_t mapsize, struct vm_object **objp, int nprot) +{ + struct hwt_thread *thr; + + thr = cdev->si_drv1; + + if (nprot != PROT_READ || *offset != 0) + return (ENXIO); + + *objp = thr->obj; + + return (0); +} + +static int +hwt_thread_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, + struct thread *td) +{ + struct hwt_bufptr_get *ptr_get; + struct hwt_context *ctx; + struct hwt_thread *thr; + struct hwt_owner *ho; + vm_offset_t curpage_offset; + int curpage; + int error; + + thr = dev->si_drv1; + + switch (cmd) { + case HWT_IOC_BUFPTR_GET: + ptr_get = (struct hwt_bufptr_get *)addr; + + /* Check if process is registered owner of any HWTs. */ + ho = hwt_ownerhash_lookup(td->td_proc); + if (ho == NULL) + return (ENXIO); + + ctx = hwt_owner_lookup_ctx(ho, ptr_get->pid); + if (ctx == NULL) + return (ENXIO); + + if (ctx != thr->ctx) + return (ENXIO); + + hwt_backend_read(thr, &curpage, &curpage_offset); + + error = copyout(&curpage, ptr_get->curpage, sizeof(int)); + if (error) + return (error); + error = copyout(&curpage_offset, ptr_get->curpage_offset, + sizeof(vm_offset_t)); + if (error) + return (error); + + break; + default: + break; + } + + return (0); +} + +static struct cdevsw hwt_thread_cdevsw = { + .d_version = D_VERSION, + .d_name = "hwt", + .d_open = hwt_thread_open, + .d_mmap_single = hwt_thread_mmap_single, + .d_ioctl = hwt_thread_ioctl, +}; + +int +hwt_thread_create_cdev(struct hwt_thread *thr, pid_t pid) +{ + struct make_dev_args args; + int error; + + printf("%s: pid %d tid %d\n", __func__, pid, thr->tid); + + make_dev_args_init(&args); + args.mda_devsw = &hwt_thread_cdevsw; + args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; + args.mda_uid = UID_ROOT; + args.mda_gid = GID_WHEEL; + args.mda_mode = 0660; + args.mda_si_drv1 = thr; + + error = make_dev_s(&args, &thr->cdev, "hwt_%d_%d", pid, thr->tid); + if (error != 0) + return (error); + + return (0); +} + +static int +hwt_thread_alloc_buffers(struct hwt_thread *thr) +{ + int error; + + thr->pages = malloc(sizeof(struct vm_page *) * thr->npages, + M_HWT_THREAD, M_WAITOK | M_ZERO); + + error = hwt_thread_alloc_pages(thr); + if (error) { + printf("%s: could not alloc pages\n", __func__); + return (error); + } + + return (0); +} + +void +hwt_thread_destroy_buffers(struct hwt_thread *thr) +{ + vm_page_t m; + int i; + + VM_OBJECT_WLOCK(thr->obj); + for (i = 0; i < thr->npages; i++) { + m = thr->pages[i]; + if (m == NULL) + break; + + vm_page_busy_acquire(m, 0); + cdev_pager_free_page(thr->obj, m); + m->flags &= ~PG_FICTITIOUS; + vm_page_unwire_noq(m); + vm_page_free(m); + + } + vm_pager_deallocate(thr->obj); + VM_OBJECT_WUNLOCK(thr->obj); + + free(thr->pages, M_HWT_THREAD); +} + +/* + * Called by ctx owner only. + */ +struct hwt_thread * +hwt_thread_lookup_by_tid(struct hwt_context *ctx, lwpid_t tid) +{ + struct hwt_thread *thr; + + HWT_CTX_ASSERT_LOCKED(ctx); + + LIST_FOREACH(thr, &ctx->threads, next) { + if (thr->tid == tid) + return (thr); + } + + return (NULL); +} + +/* + * To use by hwt_switch_in/out() only. + */ +struct hwt_thread * +hwt_thread_lookup(struct hwt_context *ctx, struct thread *td) +{ + struct hwt_thread *thr; + + HWT_CTX_ASSERT_LOCKED(ctx); + + LIST_FOREACH(thr, &ctx->threads, next) { + if (thr->tid == td->td_tid) { + HWT_THR_LOCK(thr); + HWT_CTX_UNLOCK(ctx); + return (thr); + } + } + + panic("thread not found"); +} + +int +hwt_thread_alloc(struct hwt_thread **thr0, size_t bufsize) +{ + struct hwt_thread *thr; + int error; + + thr = malloc(sizeof(struct hwt_thread), M_HWT_THREAD, + M_WAITOK | M_ZERO); + + thr->npages = bufsize / PAGE_SIZE; + + mtx_init(&thr->mtx, "thr", NULL, MTX_SPIN); + + refcount_init(&thr->refcnt, 1); + + error = hwt_thread_alloc_buffers(thr); + if (error) + return (error); + + *thr0 = thr; + + return (0); +} + +void +hwt_thread_free(struct hwt_thread *thr) +{ + + hwt_thread_destroy_buffers(thr); + + free(thr, M_HWT_THREAD); +} + +void +hwt_thread_insert(struct hwt_context *ctx, struct hwt_thread *thr) +{ + + HWT_CTX_ASSERT_LOCKED(ctx); + + LIST_INSERT_HEAD(&ctx->threads, thr, next); +} + +int +hwt_thread_create(struct thread *td, struct hwt_thread **thr0) +{ + struct hwt_context *ctx; + struct hwt_thread *thr; + struct proc *p; + size_t bufsize; + int error; + + p = td->td_proc; + + ctx = hwt_contexthash_lookup(p); + if (ctx == NULL) + return (ENXIO); + bufsize = ctx->bufsize; + HWT_CTX_UNLOCK(ctx); + + dprintf("%s: NEW thread %p, tid %d\n", __func__, td, + td->td_tid); + + error = hwt_thread_alloc(&thr, bufsize); + if (error) { + printf("%s: could not allocate thread, error %d\n", + __func__, error); + return (error); + } + + thr->tid = td->td_tid; + + error = hwt_thread_create_cdev(thr, p->p_pid); + if (error) { + printf("%s: could not create cdev, error %d\n", + __func__, error); + return (error); + } + + ctx = hwt_contexthash_lookup(p); + if (ctx == NULL) { + /* TODO: deallocate resources. */ + return (ENXIO); + } + thr->ctx = ctx; + thr->thread_id = atomic_fetchadd_int(&ctx->thread_counter, 1); + LIST_INSERT_HEAD(&ctx->threads, thr, next); + HWT_CTX_UNLOCK(ctx); + + *thr0 = thr; + + return (0); +} Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include "opt_capsicum.h" +#include "opt_hwt_hooks.h" #include #include @@ -83,6 +84,10 @@ #include #include +#ifdef HWT_HOOKS +#include +#endif + #if __has_feature(capabilities) #include #endif @@ -1609,6 +1614,18 @@ imgp->interp_start = 0; imgp->interp_end = 0; +#ifdef HWT_HOOKS + /* HWT: record main binary. */ + struct hwt_record_entry ent; + if (td->td_proc->p_flag2 & P2_HWT) { + ent.fullpath = imgp->execpath; + ent.addr = (uintptr_t)entry; + ent.size = (size_t)(imgp->end_addr - imgp->start_addr); + ent.record_type = HWT_RECORD_EXECUTABLE; + HWT_CALL_HOOK(td, HWT_EXEC, &ent); + } +#endif + if (interp != NULL) { VOP_UNLOCK(imgp->vp); if ((map->flags & MAP_ASLR) != 0) { @@ -1624,6 +1641,19 @@ vn_lock(imgp->vp, LK_SHARED | LK_RETRY); if (error != 0) goto ret; + +#ifdef HWT_HOOKS + /* HWT: Record interp. */ + struct hwt_record_entry ent; + if (td->td_proc->p_flag2 & P2_HWT) { + ent.fullpath = interp; + ent.addr = (uintptr_t)imgp->entry_addr; + ent.size = (size_t)(imgp->interp_end - + imgp->interp_start); + ent.record_type = HWT_RECORD_INTERP; + HWT_CALL_HOOK(td, HWT_EXEC, &ent); + } +#endif } else addr = imgp->et_dyn_addr; Index: sys/kern/kern_hwt.c =================================================================== --- /dev/null +++ sys/kern/kern_hwt.c @@ -0,0 +1,46 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +void __read_mostly (*hwt_hook)(struct thread *td, int func, void *arg) = NULL; Index: sys/kern/kern_thr.c =================================================================== --- sys/kern/kern_thr.c +++ sys/kern/kern_thr.c @@ -31,6 +31,7 @@ #include "opt_posix.h" #include "opt_hwpmc_hooks.h" +#include "opt_hwt_hooks.h" #include #include #include @@ -59,6 +60,9 @@ #ifdef HWPMC_HOOKS #include #endif +#ifdef HWT_HOOKS +#include +#endif #include @@ -269,6 +273,10 @@ PMC_CALL_HOOK_UNLOCKED(newtd, PMC_FN_THR_CREATE_LOG, NULL); #endif +#ifdef HWT_HOOKS + HWT_CALL_HOOK(newtd, HWT_THREAD_CREATE, NULL); +#endif + tidhash_add(newtd); /* ignore timesharing class */ @@ -611,6 +619,9 @@ if (PMC_PROC_IS_USING_PMCS(p) || PMC_SYSTEM_SAMPLING_ACTIVE()) PMC_CALL_HOOK_UNLOCKED(ttd, PMC_FN_THR_CREATE_LOG, NULL); #endif +#ifdef HWT_HOOKS + HWT_CALL_HOOK(ttd, HWT_THREAD_SET_NAME, NULL); +#endif #ifdef KTR sched_clear_tdname(ttd); #endif Index: sys/kern/kern_thread.c =================================================================== --- sys/kern/kern_thread.c +++ sys/kern/kern_thread.c @@ -30,6 +30,7 @@ #include "opt_witness.h" #include "opt_hwpmc_hooks.h" +#include "opt_hwt_hooks.h" #include __FBSDID("$FreeBSD$"); @@ -63,6 +64,9 @@ #ifdef HWPMC_HOOKS #include #endif +#ifdef HWT_HOOKS +#include +#endif #include #include @@ -971,6 +975,11 @@ } else if (PMC_SYSTEM_SAMPLING_ACTIVE()) PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_THR_EXIT_LOG, NULL); #endif + +#ifdef HWT_HOOKS + HWT_CALL_HOOK(td, HWT_THREAD_EXIT, NULL); +#endif + PROC_UNLOCK(p); PROC_STATLOCK(p); thread_lock(td); Index: sys/kern/sched_ule.c =================================================================== --- sys/kern/sched_ule.c +++ sys/kern/sched_ule.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include "opt_hwpmc_hooks.h" +#include "opt_hwt_hooks.h" #include "opt_sched.h" #include @@ -70,6 +71,10 @@ #include #endif +#ifdef HWT_HOOKS +#include +#endif + #ifdef KDTRACE_HOOKS #include int __read_mostly dtrace_vtime_active; @@ -2294,6 +2299,12 @@ if (dtrace_vtime_active) (*dtrace_vtime_switch_func)(newtd); #endif + +#ifdef HWT_HOOKS + HWT_CALL_HOOK(td, HWT_SWITCH_OUT, NULL); + HWT_CALL_HOOK(newtd, HWT_SWITCH_IN, NULL); +#endif + td->td_oncpu = NOCPU; cpu_switch(td, newtd, mtx); cpuid = td->td_oncpu = PCPU_GET(cpuid); @@ -3123,6 +3134,10 @@ newtd = sched_throw_grab(tdq); +#ifdef HWT_HOOKS + HWT_CALL_HOOK(newtd, HWT_SWITCH_IN, NULL); +#endif + /* doesn't return */ cpu_throw(NULL, newtd); } @@ -3149,6 +3164,10 @@ newtd = sched_throw_grab(tdq); +#ifdef HWT_HOOKS + HWT_CALL_HOOK(newtd, HWT_SWITCH_IN, NULL); +#endif + /* doesn't return */ cpu_switch(td, newtd, TDQ_LOCKPTR(tdq)); } Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include "opt_hwpmc_hooks.h" +#include "opt_hwt_hooks.h" #include #include @@ -97,6 +98,10 @@ #include #endif +#ifdef HWT_HOOKS +#include +#endif + static fo_rdwr_t vn_read; static fo_rdwr_t vn_write; static fo_rdwr_t vn_io_fault; @@ -2922,6 +2927,26 @@ } } #endif + +#ifdef HWT_HOOKS + /* HWT: record dynamic libs. */ + struct hwt_record_entry ent; + char *fullpath; + char *freepath; + + if ((prot & VM_PROT_EXECUTE) != 0 && error == 0) { + if (vn_fullpath(vp, &fullpath, &freepath) == 0) { + ent.fullpath = fullpath; + ent.addr = (uintptr_t) *addr; + ent.size = (size_t) size; + ent.record_type = HWT_RECORD_MMAP; + HWT_CALL_HOOK(td, HWT_MMAP, &ent); + if (freepath != NULL) + free(freepath, M_TEMP); + } + } +#endif + return (error); } Index: sys/sys/hwt.h =================================================================== --- /dev/null +++ sys/sys/hwt.h @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +/* User-visible header. */ + +#include +#include +#include + +#ifndef _SYS_HWT_H_ +#define _SYS_HWT_H_ + +#define HWT_MAGIC 0x42 +#define HWT_IOC_ALLOC \ + _IOW(HWT_MAGIC, 0x00, struct hwt_alloc) +#define HWT_IOC_START \ + _IOW(HWT_MAGIC, 0x01, struct hwt_start) +#define HWT_IOC_RECORD_GET \ + _IOW(HWT_MAGIC, 0x02, struct hwt_record_get) +#define HWT_IOC_BUFPTR_GET \ + _IOW(HWT_MAGIC, 0x03, struct hwt_bufptr_get) +#define HWT_IOC_SET_CONFIG \ + _IOW(HWT_MAGIC, 0x04, struct hwt_set_config) +#define HWT_IOC_WAKEUP \ + _IOW(HWT_MAGIC, 0x05, struct hwt_wakeup) + +#define HWT_BACKEND_MAXNAMELEN 256 + +struct hwt_alloc { + size_t bufsize; + pid_t pid; + const char *backend_name; +} __aligned(16); + +struct hwt_start { + pid_t pid; +} __aligned(16); + +struct hwt_wakeup { + pid_t pid; + lwpid_t tid; +} __aligned(16); + +struct hwt_record_user_entry { + enum hwt_record_type record_type; + char fullpath[MAXPATHLEN]; + uintptr_t addr; + size_t size; + lwpid_t tid; +} __aligned(16); + +struct hwt_record_get { + struct hwt_record_user_entry *records; + int *nentries; + pid_t pid; +} __aligned(16); + +struct hwt_bufptr_get { + int *ptr; + int *curpage; + vm_offset_t *curpage_offset; + pid_t pid; /* TODO: remove this field? */ +} __aligned(16); + +struct hwt_set_config { + pid_t pid; + + /* Configuration of ctx. */ + int pause_on_mmap; + + /* The following passed to backend as is. */ + void *config; + size_t config_size; + int config_version; +} __aligned(16); + +#endif /* !_SYS_HWT_H_ */ Index: sys/sys/hwt_record.h =================================================================== --- /dev/null +++ sys/sys/hwt_record.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2023 Ruslan Bukin + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +/* User-visible header. */ + +#ifndef _SYS_HWT_RECORD_H_ +#define _SYS_HWT_RECORD_H_ + +enum hwt_record_type { + HWT_RECORD_MMAP, + HWT_RECORD_MUNMAP, + HWT_RECORD_EXECUTABLE, + HWT_RECORD_INTERP, + HWT_RECORD_THREAD_CREATE, + HWT_RECORD_THREAD_SET_NAME, +}; + +#ifdef _KERNEL +struct hwt_record_entry { + enum hwt_record_type record_type; + LIST_ENTRY(hwt_record_entry) next; + char *fullpath; + lwpid_t tid; + uintptr_t addr; + size_t size; +}; +#endif + +#endif /* !_SYS_HWT_RECORD_H_ */ Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -886,6 +886,7 @@ #define P2_WEXIT 0x00040000 /* exit just started, no external thread_single() is permitted */ +#define P2_HWT 0x00080000 /* Process is using HWT. */ /* Flags protected by proctree_lock, kept in p_treeflags. */ #define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */ Index: sys/vm/vm_mmap.c =================================================================== --- sys/vm/vm_mmap.c +++ sys/vm/vm_mmap.c @@ -110,6 +110,10 @@ #include #endif +#ifdef HWT_HOOKS +#include +#endif + #if __has_feature(capabilities) #include #endif @@ -1054,6 +1058,16 @@ #endif rv = vm_map_remove_locked(map, addr, addr + size); +#ifdef HWT_HOOKS + struct hwt_record_entry ent; + if (rv == KERN_SUCCESS) { + ent.addr = (uintptr_t) addr; + ent.size = (size_t) size; + ent.record_type = HWT_RECORD_MUNMAP; + HWT_CALL_HOOK(td, HWT_RECORD, &ent); + } +#endif + #ifdef HWPMC_HOOKS if (rv == KERN_SUCCESS && __predict_false(pmc_handled)) { /* downgrade the lock to prevent a LOR with the pmc-sx lock */