projects/linux·blob uaccess-cleanups · refs

232 lines · 6.9 KiB

1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * kmod dups - the kernel module autoloader duplicate suppressor
4 *
5 * Copyright (C) 2023 Luis Chamberlain <[email protected]>
6 */
7
8#define pr_fmt(fmt) "module: " fmt
9
10#include <linux/bug.h>
11#include <linux/cleanup.h>
12#include <linux/completion.h>
13#include <linux/container_of.h>
14#include <linux/list.h>
15#include <linux/lockdep.h>
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/mutex.h>
19#include <linux/param.h>
20#include <linux/printk.h>
21#include <linux/refcount.h>
22#include <linux/sched.h>
23#include <linux/slab.h>
24#include <linux/string.h>
25#include <linux/workqueue.h>
26
27#include "internal.h"
28
29#undef MODULE_PARAM_PREFIX
30#define MODULE_PARAM_PREFIX "module."
31static bool enable_dups_trace = IS_ENABLED(CONFIG_MODULE_DEBUG_AUTOLOAD_DUPS_TRACE);
32module_param(enable_dups_trace, bool_enable_only, 0644);
33
34/* A mutex-protected list of active kmod requests. */
35static DEFINE_MUTEX(kmod_dup_mutex);
36static LIST_HEAD(dup_kmod_reqs);
37
38struct kmod_dup_req {
39 refcount_t refcount;
40 struct list_head list;
41 char name[MODULE_NAME_LEN];
42 struct completion first_req_done;
43 struct delayed_work delete_work;
44 int dup_ret;
45};
46
47static void get_kmod_req(struct kmod_dup_req *kmod_req)
48{
49 refcount_inc(&kmod_req->refcount);
50}
51
52static void put_kmod_req(struct kmod_dup_req *kmod_req)
53{
54 if (refcount_dec_and_test(&kmod_req->refcount))
55 kfree(kmod_req);
56}
57
58DEFINE_FREE(put_kmod_req, struct kmod_dup_req *, if (_T) put_kmod_req(_T))
59
60static struct kmod_dup_req *kmod_dup_request_lookup(char *module_name)
61{
62 struct kmod_dup_req *kmod_req;
63
64 lockdep_assert_held(&kmod_dup_mutex);
65
66 list_for_each_entry(kmod_req, &dup_kmod_reqs, list) {
67 if (!strcmp(kmod_req->name, module_name))
68 return kmod_req;
69 }
70
71 return NULL;
72}
73
74static void kmod_dup_request_delete(struct work_struct *work)
75{
76 struct kmod_dup_req *kmod_req;
77 kmod_req = container_of(to_delayed_work(work), struct kmod_dup_req, delete_work);
78
79 /*
80 * The typical situation is a module successully loaded. In that
81 * situation the module will be present already in userspace. If
82 * new requests come in after that, userspace will already know the
83 * module is loaded so will just return 0 right away. There is still
84 * a small chance right after we delete this entry new request_module()
85 * calls may happen after that, they can happen. These heuristics
86 * are to protect finit_module() abuse for auto-loading, if modules
87 * are still tryign to auto-load even if a module is already loaded,
88 * that's on them, and those inneficiencies should not be fixed by
89 * kmod. The inneficies there are a call to modprobe and modprobe
90 * just returning 0.
91 */
92 scoped_guard(mutex, &kmod_dup_mutex)
93 list_del(&kmod_req->list);
94
95 put_kmod_req(kmod_req);
96}
97
98static struct kmod_dup_req *alloc_kmod_req(const char *module_name)
99{
100 struct kmod_dup_req *kmod_req = kzalloc_obj(*kmod_req);
101
102 if (!kmod_req)
103 return NULL;
104
105 refcount_set(&kmod_req->refcount, 1);
106 strscpy(kmod_req->name, module_name);
107 INIT_DELAYED_WORK(&kmod_req->delete_work, kmod_dup_request_delete);
108 init_completion(&kmod_req->first_req_done);
109 return kmod_req;
110}
111
112bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
113{
114 struct kmod_dup_req *kmod_req __free(put_kmod_req) = NULL;
115 int ret;
116
117 scoped_guard(mutex, &kmod_dup_mutex) {
118 struct kmod_dup_req *new_kmod_req;
119
120 kmod_req = kmod_dup_request_lookup(module_name);
121 if (kmod_req) {
122 get_kmod_req(kmod_req);
123 break;
124 }
125
126 /*
127 * If the first request that came through for a module
128 * was with request_module_nowait() we cannot wait for it
129 * and share its return value with other users which may
130 * have used request_module() and need a proper return value
131 * so just skip using them as an anchor.
132 *
133 * If a prior request to this one came through with
134 * request_module() though, then a request_module_nowait()
135 * would benefit from duplicate detection.
136 */
137 if (!wait) {
138 pr_debug("New request_module_nowait() for %s -- cannot track duplicates for this request\n", module_name);
139 return false;
140 }
141
142 /*
143 * There was no duplicate, just add the request so we can
144 * keep tab on duplicates later.
145 */
146 pr_debug("New request_module() for %s\n", module_name);
147 new_kmod_req = alloc_kmod_req(module_name);
148 if (!new_kmod_req)
149 return false;
150 list_add(&new_kmod_req->list, &dup_kmod_reqs);
151 return false;
152 }
153
154 /* We are dealing with a duplicate request now */
155
156 /*
157 * To fix these try to use try_then_request_module() instead as that
158 * will check if the component you are looking for is present or not.
159 * You could also just queue a single request to load the module once,
160 * instead of having each and everything you need try to request for
161 * the module.
162 *
163 * Duplicate request_module() calls can cause quite a bit of wasted
164 * vmalloc() space when racing with userspace.
165 */
166 if (enable_dups_trace)
167 WARN(1, "module-autoload: duplicate request for module %s\n", module_name);
168 else
169 pr_warn("module-autoload: duplicate request for module %s\n", module_name);
170
171 if (!wait) {
172 /*
173 * If request_module_nowait() was used then the user just
174 * wanted to issue the request and if another module request
175 * was already its way with the same name we don't care for
176 * the return value either. Let duplicate request_module_nowait()
177 * calls bail out right away.
178 */
179 *dup_ret = 0;
180 return true;
181 }
182
183 /*
184 * If a duplicate request_module() was used they *may* care for
185 * the return value, so we have no other option but to wait for
186 * the first caller to complete. If the first caller used
187 * the request_module_nowait() call, subsquent callers will
188 * deal with the comprmise of getting a successful call with this
189 * optimization enabled ...
190 */
191 ret = wait_for_completion_state(&kmod_req->first_req_done,
192 TASK_KILLABLE);
193 if (ret) {
194 *dup_ret = ret;
195 return true;
196 }
197
198 /* Now the duplicate request has the same exact return value as the first request */
199 *dup_ret = kmod_req->dup_ret;
200 return true;
201}
202
203void kmod_dup_request_announce(char *module_name, int ret)
204{
205 struct kmod_dup_req *kmod_req;
206
207 /*
208 * Look for a kmod_dup_req previously added in
209 * kmod_dup_request_exists_wait(). Note that a request_module_nowait()
210 * without its own kmod_dup_req entry can announce a result of
211 * a concurrent request_module() call.
212 */
213 scoped_guard(mutex, &kmod_dup_mutex) {
214 kmod_req = kmod_dup_request_lookup(module_name);
215 if (!kmod_req || completion_done(&kmod_req->first_req_done))
216 return;
217
218 kmod_req->dup_ret = ret;
219
220 /* Inform all duplicate waiters to check the return value. */
221 complete_all(&kmod_req->first_req_done);
222 }
223
224 /*
225 * Now that we have allowed prior request_module() calls to go on
226 * with life, let's schedule deleting this entry. We don't have
227 * to do it right away, but we *eventually* want to do it so to not
228 * let this linger forever as this is just a boot optimization for
229 * possible abuses of vmalloc() incurred by finit_module() thrashing.
230 */
231 queue_delayed_work(system_dfl_wq, &kmod_req->delete_work, 60 * HZ);
232}