Blame view

kernel/kmod.c 5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
235586939   Luis R. Rodriguez   kmod: split out u...
2
3
   * kmod - the kernel module loader
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
  #include <linux/module.h>
  #include <linux/sched.h>
299300258   Ingo Molnar   sched/headers: Pr...
6
  #include <linux/sched/task.h>
5c2c5c551   Ingo Molnar   sched/headers, vf...
7
  #include <linux/binfmts.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
  #include <linux/syscalls.h>
  #include <linux/unistd.h>
  #include <linux/kmod.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/completion.h>
17f60a7da   Eric Paris   capabilites: allo...
13
  #include <linux/cred.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/file.h>
9f3acc314   Al Viro   [PATCH] split lin...
15
  #include <linux/fdtable.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
  #include <linux/workqueue.h>
  #include <linux/security.h>
  #include <linux/mount.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
d025c9db7   Andi Kleen   [PATCH] Support p...
21
  #include <linux/resource.h>
8cdd4936c   Rafael J. Wysocki   PM: disable userm...
22
23
  #include <linux/notifier.h>
  #include <linux/suspend.h>
b298d289c   Srivatsa S. Bhat   PM / Sleep: Fix f...
24
  #include <linux/rwsem.h>
a74fb73c1   Al Viro   infrastructure fo...
25
  #include <linux/ptrace.h>
0fdff3ec6   Tejun Heo   async, kmod: warn...
26
  #include <linux/async.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
27
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

7ead8b831   Li Zefan   tracing/events: A...
29
  #include <trace/events/module.h>
165d1cc00   Luis R. Rodriguez   kmod: reduce atom...
30
31
32
33
34
35
36
  /*
   * Assuming:
   *
   * threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE,
   *		       (u64) THREAD_SIZE * 8UL);
   *
   * If you need less than 50 threads would mean we're dealing with systems
06d4f8152   Qiujun Huang   kernel/kmod.c: fi...
37
   * smaller than 3200 pages. This assumes you are capable of having ~13M memory,
6f9e148c2   Tiezhu Yang   kmod: remove redu...
38
39
   * and this would only be an upper limit, after which the OOM killer would take
   * effect. Systems like these are very unlikely if modules are enabled.
165d1cc00   Luis R. Rodriguez   kmod: reduce atom...
40
41
42
   */
  #define MAX_KMOD_CONCURRENT 50
  static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT);
6d7964a72   Luis R. Rodriguez   kmod: throttle km...
43
  static DECLARE_WAIT_QUEUE_HEAD(kmod_wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
  
  /*
2ba293c9e   Luis R. Rodriguez   kmod: fix wait on...
46
47
48
49
50
51
52
53
54
55
56
57
   * This is a restriction on having *all* MAX_KMOD_CONCURRENT threads
   * running at the same time without returning. When this happens we
   * believe you've somehow ended up with a recursive module dependency
   * creating a loop.
   *
   * We have no option but to fail.
   *
   * Userspace should proactively try to detect and prevent these.
   */
  #define MAX_KMOD_ALL_BUSY_TIMEOUT 5
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  	modprobe_path is set via /proc/sys.
  */
  char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
1cc684ab7   Oleg Nesterov   kmod: make __requ...
61
62
63
64
65
  static void free_modprobe_argv(struct subprocess_info *info)
  {
  	kfree(info->argv[3]); /* check call_modprobe() */
  	kfree(info->argv);
  }
3e63a93b9   Oleg Nesterov   kmod: introduce c...
66
67
  static int call_modprobe(char *module_name, int wait)
  {
f634460c9   Lucas De Marchi   kmod: split call ...
68
  	struct subprocess_info *info;
3e63a93b9   Oleg Nesterov   kmod: introduce c...
69
70
71
72
73
74
  	static char *envp[] = {
  		"HOME=/",
  		"TERM=linux",
  		"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
  		NULL
  	};
1cc684ab7   Oleg Nesterov   kmod: make __requ...
75
76
77
78
79
80
81
82
83
84
85
86
87
  	char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL);
  	if (!argv)
  		goto out;
  
  	module_name = kstrdup(module_name, GFP_KERNEL);
  	if (!module_name)
  		goto free_argv;
  
  	argv[0] = modprobe_path;
  	argv[1] = "-q";
  	argv[2] = "--";
  	argv[3] = module_name;	/* check free_modprobe_argv() */
  	argv[4] = NULL;
3e63a93b9   Oleg Nesterov   kmod: introduce c...
88

f634460c9   Lucas De Marchi   kmod: split call ...
89
90
91
92
93
94
95
96
97
  	info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL,
  					 NULL, free_modprobe_argv, NULL);
  	if (!info)
  		goto free_module_name;
  
  	return call_usermodehelper_exec(info, wait | UMH_KILLABLE);
  
  free_module_name:
  	kfree(module_name);
1cc684ab7   Oleg Nesterov   kmod: make __requ...
98
99
100
101
  free_argv:
  	kfree(argv);
  out:
  	return -ENOMEM;
3e63a93b9   Oleg Nesterov   kmod: introduce c...
102
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  /**
acae05156   Arjan van de Ven   module: create a ...
104
105
   * __request_module - try to load a kernel module
   * @wait: wait (or not) for the operation to complete
bd4207c90   Randy Dunlap   kmod: fix varargs...
106
107
   * @fmt: printf style format string for the name of the module
   * @...: arguments as specified in the format string
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
   *
   * Load a module using the user mode module loader. The function returns
60b61a6f4   NeilBrown   kmod: correct doc...
110
111
112
113
114
   * zero on success or a negative errno code or positive exit code from
   * "modprobe" on failure. Note that a successful module load does not mean
   * the module did not then unload and exit on an error of its own. Callers
   * must check that the service they requested is now available not blindly
   * invoke it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
   *
   * If module auto-loading support is disabled then this function
d7d27cfc5   Eric Biggers   kmod: make reques...
117
   * simply returns -ENOENT.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
   */
acae05156   Arjan van de Ven   module: create a ...
119
  int __request_module(bool wait, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  {
  	va_list args;
  	char module_name[MODULE_NAME_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124

0fdff3ec6   Tejun Heo   async, kmod: warn...
125
126
127
128
129
130
131
  	/*
  	 * We don't allow synchronous module loading from async.  Module
  	 * init may invoke async_synchronize_full() which will end up
  	 * waiting for this task which already is waiting for the module
  	 * loading to complete, leading to a deadlock.
  	 */
  	WARN_ON_ONCE(wait && current_is_async());
7f57cfa4e   Oleg Nesterov   usermodehelper: k...
132
  	if (!modprobe_path[0])
d7d27cfc5   Eric Biggers   kmod: make reques...
133
  		return -ENOENT;
7f57cfa4e   Oleg Nesterov   usermodehelper: k...
134

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
  	va_start(args, fmt);
  	ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
  	va_end(args);
  	if (ret >= MODULE_NAME_LEN)
  		return -ENAMETOOLONG;
dd8dbf2e6   Eric Paris   security: report ...
140
141
142
  	ret = security_kernel_module_request(module_name);
  	if (ret)
  		return ret;
165d1cc00   Luis R. Rodriguez   kmod: reduce atom...
143
  	if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) {
6d7964a72   Luis R. Rodriguez   kmod: throttle km...
144
145
146
  		pr_warn_ratelimited("request_module: kmod_concurrent_max (%u) close to 0 (max_modprobes: %u), for module %s, throttling...",
  				    atomic_read(&kmod_concurrent_max),
  				    MAX_KMOD_CONCURRENT, module_name);
2ba293c9e   Luis R. Rodriguez   kmod: fix wait on...
147
148
149
150
151
152
153
154
155
156
157
  		ret = wait_event_killable_timeout(kmod_wq,
  						  atomic_dec_if_positive(&kmod_concurrent_max) >= 0,
  						  MAX_KMOD_ALL_BUSY_TIMEOUT * HZ);
  		if (!ret) {
  			pr_warn_ratelimited("request_module: modprobe %s cannot be processed, kmod busy with %d threads for more than %d seconds now",
  					    module_name, MAX_KMOD_CONCURRENT, MAX_KMOD_ALL_BUSY_TIMEOUT);
  			return -ETIME;
  		} else if (ret == -ERESTARTSYS) {
  			pr_warn_ratelimited("request_module: sigkill sent for modprobe %s, giving up", module_name);
  			return ret;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	}
7ead8b831   Li Zefan   tracing/events: A...
159
  	trace_module_request(module_name, wait, _RET_IP_);
3e63a93b9   Oleg Nesterov   kmod: introduce c...
160
  	ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
a06a4dc3a   Neil Horman   kmod: add init fu...
161

165d1cc00   Luis R. Rodriguez   kmod: reduce atom...
162
  	atomic_inc(&kmod_concurrent_max);
6d7964a72   Luis R. Rodriguez   kmod: throttle km...
163
  	wake_up(&kmod_wq);
165d1cc00   Luis R. Rodriguez   kmod: reduce atom...
164

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  	return ret;
  }
acae05156   Arjan van de Ven   module: create a ...
167
  EXPORT_SYMBOL(__request_module);