Path: blob/master/tools/perf/bench/sched-seccomp-notify.c
26285 views
// SPDX-License-Identifier: GPL-2.01#include <subcmd/parse-options.h>2#include "bench.h"34#include <uapi/linux/filter.h>5#include <sys/types.h>6#include <sys/time.h>7#include <linux/unistd.h>8#include <sys/syscall.h>9#include <sys/ioctl.h>10#include <linux/time64.h>11#include <uapi/linux/seccomp.h>12#include <sys/prctl.h>1314#include <unistd.h>15#include <limits.h>16#include <stddef.h>17#include <stdint.h>18#include <stdio.h>19#include <stdlib.h>20#include <signal.h>21#include <sys/wait.h>22#include <string.h>23#include <errno.h>24#include <err.h>25#include <inttypes.h>2627#define LOOPS_DEFAULT 1000000UL28static uint64_t loops = LOOPS_DEFAULT;29static bool sync_mode;3031static const struct option options[] = {32OPT_U64('l', "loop", &loops, "Specify number of loops"),33OPT_BOOLEAN('s', "sync-mode", &sync_mode,34"Enable the synchronous mode for seccomp notifications"),35OPT_END()36};3738static const char * const bench_seccomp_usage[] = {39"perf bench sched secccomp-notify <options>",40NULL41};4243static int seccomp(unsigned int op, unsigned int flags, void *args)44{45return syscall(__NR_seccomp, op, flags, args);46}4748static int user_notif_syscall(int nr, unsigned int flags)49{50struct sock_filter filter[] = {51BPF_STMT(BPF_LD|BPF_W|BPF_ABS,52offsetof(struct seccomp_data, nr)),53BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, nr, 0, 1),54BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_USER_NOTIF),55BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),56};5758struct sock_fprog prog = {59.len = (unsigned short)ARRAY_SIZE(filter),60.filter = filter,61};6263return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog);64}6566#define USER_NOTIF_MAGIC INT_MAX67static void user_notification_sync_loop(int listener)68{69struct seccomp_notif_resp resp;70struct seccomp_notif req;71uint64_t nr;7273for (nr = 0; nr < loops; nr++) {74memset(&req, 0, sizeof(req));75if (ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req))76err(EXIT_FAILURE, "SECCOMP_IOCTL_NOTIF_RECV failed");7778if (req.data.nr != __NR_gettid)79errx(EXIT_FAILURE, "unexpected syscall: %d", req.data.nr);8081resp.id = req.id;82resp.error = 0;83resp.val = USER_NOTIF_MAGIC;84resp.flags = 0;85if (ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp))86err(EXIT_FAILURE, "SECCOMP_IOCTL_NOTIF_SEND failed");87}88}8990#ifndef SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP91#define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0)92#define SECCOMP_IOCTL_NOTIF_SET_FLAGS SECCOMP_IOW(4, __u64)93#endif94int bench_sched_seccomp_notify(int argc, const char **argv)95{96struct timeval start, stop, diff;97unsigned long long result_usec = 0;98int status, listener;99pid_t pid;100long ret;101102argc = parse_options(argc, argv, options, bench_seccomp_usage, 0);103104gettimeofday(&start, NULL);105106prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);107listener = user_notif_syscall(__NR_gettid,108SECCOMP_FILTER_FLAG_NEW_LISTENER);109if (listener < 0)110err(EXIT_FAILURE, "can't create a notification descriptor");111112pid = fork();113if (pid < 0)114err(EXIT_FAILURE, "fork");115if (pid == 0) {116if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0))117err(EXIT_FAILURE, "can't set the parent death signal");118while (1) {119ret = syscall(__NR_gettid);120if (ret == USER_NOTIF_MAGIC)121continue;122break;123}124_exit(1);125}126127if (sync_mode) {128if (ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS,129SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP, 0))130err(EXIT_FAILURE,131"can't set SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP");132}133user_notification_sync_loop(listener);134135kill(pid, SIGKILL);136if (waitpid(pid, &status, 0) != pid)137err(EXIT_FAILURE, "waitpid(%d) failed", pid);138if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL)139errx(EXIT_FAILURE, "unexpected exit code: %d", status);140141gettimeofday(&stop, NULL);142timersub(&stop, &start, &diff);143144switch (bench_format) {145case BENCH_FORMAT_DEFAULT:146printf("# Executed %" PRIu64 " system calls\n\n",147loops);148149result_usec = diff.tv_sec * USEC_PER_SEC;150result_usec += diff.tv_usec;151152printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",153(unsigned long) diff.tv_sec,154(unsigned long) (diff.tv_usec / USEC_PER_MSEC));155156printf(" %14lf usecs/op\n",157(double)result_usec / (double)loops);158printf(" %14d ops/sec\n",159(int)((double)loops /160((double)result_usec / (double)USEC_PER_SEC)));161break;162163case BENCH_FORMAT_SIMPLE:164printf("%lu.%03lu\n",165(unsigned long) diff.tv_sec,166(unsigned long) (diff.tv_usec / USEC_PER_MSEC));167break;168169default:170/* reaching here is something disaster */171fprintf(stderr, "Unknown format:%d\n", bench_format);172exit(1);173break;174}175176return 0;177}178179180