Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1// SPDX-License-Identifier: GPL-2.0
  2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  3#include <linux/init.h>
  4#include <linux/module.h>
  5#include <linux/umh.h>
  6#include <linux/bpfilter.h>
  7#include <linux/sched.h>
  8#include <linux/sched/signal.h>
  9#include <linux/fs.h>
 10#include <linux/file.h>
 11#include "msgfmt.h"
 12
 13extern char bpfilter_umh_start;
 14extern char bpfilter_umh_end;
 15
 16static void shutdown_umh(void)
 17{
 18	struct umd_info *info = &bpfilter_ops.info;
 19	struct pid *tgid = info->tgid;
 20
 21	if (tgid) {
 22		kill_pid(tgid, SIGKILL, 1);
 23		wait_event(tgid->wait_pidfd, thread_group_exited(tgid));
 24		bpfilter_umh_cleanup(info);
 25	}
 26}
 27
 28static void __stop_umh(void)
 29{
 30	if (IS_ENABLED(CONFIG_INET))
 31		shutdown_umh();
 32}
 33
 34static int bpfilter_send_req(struct mbox_request *req)
 35{
 36	struct mbox_reply reply;
 37	loff_t pos = 0;
 38	ssize_t n;
 39
 40	if (!bpfilter_ops.info.tgid)
 41		return -EFAULT;
 42	pos = 0;
 43	n = kernel_write(bpfilter_ops.info.pipe_to_umh, req, sizeof(*req),
 44			   &pos);
 45	if (n != sizeof(*req)) {
 46		pr_err("write fail %zd\n", n);
 47		goto stop;
 48	}
 49	pos = 0;
 50	n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
 51			&pos);
 52	if (n != sizeof(reply)) {
 53		pr_err("read fail %zd\n", n);
 54		goto stop;
 55	}
 56	return reply.status;
 57stop:
 58	__stop_umh();
 59	return -EFAULT;
 60}
 61
 62static int bpfilter_process_sockopt(struct sock *sk, int optname,
 63				    sockptr_t optval, unsigned int optlen,
 64				    bool is_set)
 65{
 66	struct mbox_request req = {
 67		.is_set		= is_set,
 68		.pid		= current->pid,
 69		.cmd		= optname,
 70		.addr		= (uintptr_t)optval.user,
 71		.len		= optlen,
 72	};
 73	if (uaccess_kernel() || sockptr_is_kernel(optval)) {
 74		pr_err("kernel access not supported\n");
 75		return -EFAULT;
 76	}
 77	return bpfilter_send_req(&req);
 78}
 79
 80static int start_umh(void)
 81{
 82	struct mbox_request req = { .pid = current->pid };
 83	int err;
 84
 85	/* fork usermode process */
 86	err = fork_usermode_driver(&bpfilter_ops.info);
 87	if (err)
 88		return err;
 89	pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
 90
 91	/* health check that usermode process started correctly */
 92	if (bpfilter_send_req(&req) != 0) {
 93		shutdown_umh();
 94		return -EFAULT;
 95	}
 96
 97	return 0;
 98}
 99
100static int __init load_umh(void)
101{
102	int err;
103
104	err = umd_load_blob(&bpfilter_ops.info,
105			    &bpfilter_umh_start,
106			    &bpfilter_umh_end - &bpfilter_umh_start);
107	if (err)
108		return err;
109
110	mutex_lock(&bpfilter_ops.lock);
111	err = start_umh();
112	if (!err && IS_ENABLED(CONFIG_INET)) {
113		bpfilter_ops.sockopt = &bpfilter_process_sockopt;
114		bpfilter_ops.start = &start_umh;
115	}
116	mutex_unlock(&bpfilter_ops.lock);
117	if (err)
118		umd_unload_blob(&bpfilter_ops.info);
119	return err;
120}
121
122static void __exit fini_umh(void)
123{
124	mutex_lock(&bpfilter_ops.lock);
125	if (IS_ENABLED(CONFIG_INET)) {
126		shutdown_umh();
127		bpfilter_ops.start = NULL;
128		bpfilter_ops.sockopt = NULL;
129	}
130	mutex_unlock(&bpfilter_ops.lock);
131
132	umd_unload_blob(&bpfilter_ops.info);
133}
134module_init(load_umh);
135module_exit(fini_umh);
136MODULE_LICENSE("GPL");