diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit.c | 216 | ||||
-rw-r--r-- | kernel/auditfilter.c | 9 | ||||
-rw-r--r-- | kernel/auditsc.c | 40 | ||||
-rw-r--r-- | kernel/kmod.c | 120 | ||||
-rw-r--r-- | kernel/module.c | 47 | ||||
-rw-r--r-- | kernel/params.c | 29 | ||||
-rw-r--r-- | kernel/printk.c | 2 |
7 files changed, 367 insertions, 96 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index d9b690ac684b..76c9a11b72d6 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Gateway between the kernel (e.g., selinux) and the user-space audit daemon. | 2 | * Gateway between the kernel (e.g., selinux) and the user-space audit daemon. |
3 | * System-call specific features have moved to auditsc.c | 3 | * System-call specific features have moved to auditsc.c |
4 | * | 4 | * |
5 | * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. | 5 | * Copyright 2003-2007 Red Hat Inc., Durham, North Carolina. |
6 | * All Rights Reserved. | 6 | * All Rights Reserved. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
@@ -65,7 +65,9 @@ | |||
65 | * (Initialization happens after skb_init is called.) */ | 65 | * (Initialization happens after skb_init is called.) */ |
66 | static int audit_initialized; | 66 | static int audit_initialized; |
67 | 67 | ||
68 | /* No syscall auditing will take place unless audit_enabled != 0. */ | 68 | /* 0 - no auditing |
69 | * 1 - auditing enabled | ||
70 | * 2 - auditing enabled and configuration is locked/unchangeable. */ | ||
69 | int audit_enabled; | 71 | int audit_enabled; |
70 | 72 | ||
71 | /* Default state when kernel boots without any parameters. */ | 73 | /* Default state when kernel boots without any parameters. */ |
@@ -239,102 +241,150 @@ void audit_log_lost(const char *message) | |||
239 | 241 | ||
240 | static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid) | 242 | static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid) |
241 | { | 243 | { |
242 | int old = audit_rate_limit; | 244 | int res, rc = 0, old = audit_rate_limit; |
245 | |||
246 | /* check if we are locked */ | ||
247 | if (audit_enabled == 2) | ||
248 | res = 0; | ||
249 | else | ||
250 | res = 1; | ||
243 | 251 | ||
244 | if (sid) { | 252 | if (sid) { |
245 | char *ctx = NULL; | 253 | char *ctx = NULL; |
246 | u32 len; | 254 | u32 len; |
247 | int rc; | 255 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
248 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
249 | return rc; | ||
250 | else | ||
251 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 256 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
252 | "audit_rate_limit=%d old=%d by auid=%u subj=%s", | 257 | "audit_rate_limit=%d old=%d by auid=%u" |
253 | limit, old, loginuid, ctx); | 258 | " subj=%s res=%d", |
254 | kfree(ctx); | 259 | limit, old, loginuid, ctx, res); |
255 | } else | 260 | kfree(ctx); |
256 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 261 | } else |
257 | "audit_rate_limit=%d old=%d by auid=%u", | 262 | res = 0; /* Something weird, deny request */ |
258 | limit, old, loginuid); | 263 | } |
259 | audit_rate_limit = limit; | 264 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
260 | return 0; | 265 | "audit_rate_limit=%d old=%d by auid=%u res=%d", |
266 | limit, old, loginuid, res); | ||
267 | |||
268 | /* If we are allowed, make the change */ | ||
269 | if (res == 1) | ||
270 | audit_rate_limit = limit; | ||
271 | /* Not allowed, update reason */ | ||
272 | else if (rc == 0) | ||
273 | rc = -EPERM; | ||
274 | return rc; | ||
261 | } | 275 | } |
262 | 276 | ||
263 | static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid) | 277 | static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid) |
264 | { | 278 | { |
265 | int old = audit_backlog_limit; | 279 | int res, rc = 0, old = audit_backlog_limit; |
280 | |||
281 | /* check if we are locked */ | ||
282 | if (audit_enabled == 2) | ||
283 | res = 0; | ||
284 | else | ||
285 | res = 1; | ||
266 | 286 | ||
267 | if (sid) { | 287 | if (sid) { |
268 | char *ctx = NULL; | 288 | char *ctx = NULL; |
269 | u32 len; | 289 | u32 len; |
270 | int rc; | 290 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
271 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
272 | return rc; | ||
273 | else | ||
274 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 291 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
275 | "audit_backlog_limit=%d old=%d by auid=%u subj=%s", | 292 | "audit_backlog_limit=%d old=%d by auid=%u" |
276 | limit, old, loginuid, ctx); | 293 | " subj=%s res=%d", |
277 | kfree(ctx); | 294 | limit, old, loginuid, ctx, res); |
278 | } else | 295 | kfree(ctx); |
279 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 296 | } else |
280 | "audit_backlog_limit=%d old=%d by auid=%u", | 297 | res = 0; /* Something weird, deny request */ |
281 | limit, old, loginuid); | 298 | } |
282 | audit_backlog_limit = limit; | 299 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
283 | return 0; | 300 | "audit_backlog_limit=%d old=%d by auid=%u res=%d", |
301 | limit, old, loginuid, res); | ||
302 | |||
303 | /* If we are allowed, make the change */ | ||
304 | if (res == 1) | ||
305 | audit_backlog_limit = limit; | ||
306 | /* Not allowed, update reason */ | ||
307 | else if (rc == 0) | ||
308 | rc = -EPERM; | ||
309 | return rc; | ||
284 | } | 310 | } |
285 | 311 | ||
286 | static int audit_set_enabled(int state, uid_t loginuid, u32 sid) | 312 | static int audit_set_enabled(int state, uid_t loginuid, u32 sid) |
287 | { | 313 | { |
288 | int old = audit_enabled; | 314 | int res, rc = 0, old = audit_enabled; |
289 | 315 | ||
290 | if (state != 0 && state != 1) | 316 | if (state < 0 || state > 2) |
291 | return -EINVAL; | 317 | return -EINVAL; |
292 | 318 | ||
319 | /* check if we are locked */ | ||
320 | if (audit_enabled == 2) | ||
321 | res = 0; | ||
322 | else | ||
323 | res = 1; | ||
324 | |||
293 | if (sid) { | 325 | if (sid) { |
294 | char *ctx = NULL; | 326 | char *ctx = NULL; |
295 | u32 len; | 327 | u32 len; |
296 | int rc; | 328 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
297 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
298 | return rc; | ||
299 | else | ||
300 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 329 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
301 | "audit_enabled=%d old=%d by auid=%u subj=%s", | 330 | "audit_enabled=%d old=%d by auid=%u" |
302 | state, old, loginuid, ctx); | 331 | " subj=%s res=%d", |
303 | kfree(ctx); | 332 | state, old, loginuid, ctx, res); |
304 | } else | 333 | kfree(ctx); |
305 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 334 | } else |
306 | "audit_enabled=%d old=%d by auid=%u", | 335 | res = 0; /* Something weird, deny request */ |
307 | state, old, loginuid); | 336 | } |
308 | audit_enabled = state; | 337 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
309 | return 0; | 338 | "audit_enabled=%d old=%d by auid=%u res=%d", |
339 | state, old, loginuid, res); | ||
340 | |||
341 | /* If we are allowed, make the change */ | ||
342 | if (res == 1) | ||
343 | audit_enabled = state; | ||
344 | /* Not allowed, update reason */ | ||
345 | else if (rc == 0) | ||
346 | rc = -EPERM; | ||
347 | return rc; | ||
310 | } | 348 | } |
311 | 349 | ||
312 | static int audit_set_failure(int state, uid_t loginuid, u32 sid) | 350 | static int audit_set_failure(int state, uid_t loginuid, u32 sid) |
313 | { | 351 | { |
314 | int old = audit_failure; | 352 | int res, rc = 0, old = audit_failure; |
315 | 353 | ||
316 | if (state != AUDIT_FAIL_SILENT | 354 | if (state != AUDIT_FAIL_SILENT |
317 | && state != AUDIT_FAIL_PRINTK | 355 | && state != AUDIT_FAIL_PRINTK |
318 | && state != AUDIT_FAIL_PANIC) | 356 | && state != AUDIT_FAIL_PANIC) |
319 | return -EINVAL; | 357 | return -EINVAL; |
320 | 358 | ||
359 | /* check if we are locked */ | ||
360 | if (audit_enabled == 2) | ||
361 | res = 0; | ||
362 | else | ||
363 | res = 1; | ||
364 | |||
321 | if (sid) { | 365 | if (sid) { |
322 | char *ctx = NULL; | 366 | char *ctx = NULL; |
323 | u32 len; | 367 | u32 len; |
324 | int rc; | 368 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
325 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
326 | return rc; | ||
327 | else | ||
328 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 369 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
329 | "audit_failure=%d old=%d by auid=%u subj=%s", | 370 | "audit_failure=%d old=%d by auid=%u" |
330 | state, old, loginuid, ctx); | 371 | " subj=%s res=%d", |
331 | kfree(ctx); | 372 | state, old, loginuid, ctx, res); |
332 | } else | 373 | kfree(ctx); |
333 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 374 | } else |
334 | "audit_failure=%d old=%d by auid=%u", | 375 | res = 0; /* Something weird, deny request */ |
335 | state, old, loginuid); | 376 | } |
336 | audit_failure = state; | 377 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
337 | return 0; | 378 | "audit_failure=%d old=%d by auid=%u res=%d", |
379 | state, old, loginuid, res); | ||
380 | |||
381 | /* If we are allowed, make the change */ | ||
382 | if (res == 1) | ||
383 | audit_failure = state; | ||
384 | /* Not allowed, update reason */ | ||
385 | else if (rc == 0) | ||
386 | rc = -EPERM; | ||
387 | return rc; | ||
338 | } | 388 | } |
339 | 389 | ||
340 | static int kauditd_thread(void *dummy) | 390 | static int kauditd_thread(void *dummy) |
@@ -599,6 +649,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
599 | case AUDIT_DEL: | 649 | case AUDIT_DEL: |
600 | if (nlmsg_len(nlh) < sizeof(struct audit_rule)) | 650 | if (nlmsg_len(nlh) < sizeof(struct audit_rule)) |
601 | return -EINVAL; | 651 | return -EINVAL; |
652 | if (audit_enabled == 2) { | ||
653 | ab = audit_log_start(NULL, GFP_KERNEL, | ||
654 | AUDIT_CONFIG_CHANGE); | ||
655 | if (ab) { | ||
656 | audit_log_format(ab, | ||
657 | "pid=%d uid=%u auid=%u", | ||
658 | pid, uid, loginuid); | ||
659 | if (sid) { | ||
660 | if (selinux_sid_to_string( | ||
661 | sid, &ctx, &len)) { | ||
662 | audit_log_format(ab, | ||
663 | " ssid=%u", sid); | ||
664 | /* Maybe call audit_panic? */ | ||
665 | } else | ||
666 | audit_log_format(ab, | ||
667 | " subj=%s", ctx); | ||
668 | kfree(ctx); | ||
669 | } | ||
670 | audit_log_format(ab, " audit_enabled=%d res=0", | ||
671 | audit_enabled); | ||
672 | audit_log_end(ab); | ||
673 | } | ||
674 | return -EPERM; | ||
675 | } | ||
602 | /* fallthrough */ | 676 | /* fallthrough */ |
603 | case AUDIT_LIST: | 677 | case AUDIT_LIST: |
604 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, | 678 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, |
@@ -609,6 +683,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
609 | case AUDIT_DEL_RULE: | 683 | case AUDIT_DEL_RULE: |
610 | if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) | 684 | if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) |
611 | return -EINVAL; | 685 | return -EINVAL; |
686 | if (audit_enabled == 2) { | ||
687 | ab = audit_log_start(NULL, GFP_KERNEL, | ||
688 | AUDIT_CONFIG_CHANGE); | ||
689 | if (ab) { | ||
690 | audit_log_format(ab, | ||
691 | "pid=%d uid=%u auid=%u", | ||
692 | pid, uid, loginuid); | ||
693 | if (sid) { | ||
694 | if (selinux_sid_to_string( | ||
695 | sid, &ctx, &len)) { | ||
696 | audit_log_format(ab, | ||
697 | " ssid=%u", sid); | ||
698 | /* Maybe call audit_panic? */ | ||
699 | } else | ||
700 | audit_log_format(ab, | ||
701 | " subj=%s", ctx); | ||
702 | kfree(ctx); | ||
703 | } | ||
704 | audit_log_format(ab, " audit_enabled=%d res=0", | ||
705 | audit_enabled); | ||
706 | audit_log_end(ab); | ||
707 | } | ||
708 | return -EPERM; | ||
709 | } | ||
612 | /* fallthrough */ | 710 | /* fallthrough */ |
613 | case AUDIT_LIST_RULES: | 711 | case AUDIT_LIST_RULES: |
614 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, | 712 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 87865f8b4ce3..3749193aed8c 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -937,9 +937,10 @@ static void audit_update_watch(struct audit_parent *parent, | |||
937 | } | 937 | } |
938 | 938 | ||
939 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 939 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
940 | audit_log_format(ab, "audit updated rules specifying path="); | 940 | audit_log_format(ab, "op=updated rules specifying path="); |
941 | audit_log_untrustedstring(ab, owatch->path); | 941 | audit_log_untrustedstring(ab, owatch->path); |
942 | audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino); | 942 | audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino); |
943 | audit_log_format(ab, " list=%d res=1", r->listnr); | ||
943 | audit_log_end(ab); | 944 | audit_log_end(ab); |
944 | 945 | ||
945 | audit_remove_watch(owatch); | 946 | audit_remove_watch(owatch); |
@@ -969,14 +970,14 @@ static void audit_remove_parent_watches(struct audit_parent *parent) | |||
969 | e = container_of(r, struct audit_entry, rule); | 970 | e = container_of(r, struct audit_entry, rule); |
970 | 971 | ||
971 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 972 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
972 | audit_log_format(ab, "audit implicitly removed rule path="); | 973 | audit_log_format(ab, "op=remove rule path="); |
973 | audit_log_untrustedstring(ab, w->path); | 974 | audit_log_untrustedstring(ab, w->path); |
974 | if (r->filterkey) { | 975 | if (r->filterkey) { |
975 | audit_log_format(ab, " key="); | 976 | audit_log_format(ab, " key="); |
976 | audit_log_untrustedstring(ab, r->filterkey); | 977 | audit_log_untrustedstring(ab, r->filterkey); |
977 | } else | 978 | } else |
978 | audit_log_format(ab, " key=(null)"); | 979 | audit_log_format(ab, " key=(null)"); |
979 | audit_log_format(ab, " list=%d", r->listnr); | 980 | audit_log_format(ab, " list=%d res=1", r->listnr); |
980 | audit_log_end(ab); | 981 | audit_log_end(ab); |
981 | 982 | ||
982 | list_del(&r->rlist); | 983 | list_del(&r->rlist); |
@@ -1410,7 +1411,7 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action, | |||
1410 | audit_log_format(ab, " subj=%s", ctx); | 1411 | audit_log_format(ab, " subj=%s", ctx); |
1411 | kfree(ctx); | 1412 | kfree(ctx); |
1412 | } | 1413 | } |
1413 | audit_log_format(ab, " %s rule key=", action); | 1414 | audit_log_format(ab, " op=%s rule key=", action); |
1414 | if (rule->filterkey) | 1415 | if (rule->filterkey) |
1415 | audit_log_untrustedstring(ab, rule->filterkey); | 1416 | audit_log_untrustedstring(ab, rule->filterkey); |
1416 | else | 1417 | else |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 298897559ca4..359955800dd2 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -170,6 +170,11 @@ struct audit_aux_data_sockaddr { | |||
170 | char a[0]; | 170 | char a[0]; |
171 | }; | 171 | }; |
172 | 172 | ||
173 | struct audit_aux_data_fd_pair { | ||
174 | struct audit_aux_data d; | ||
175 | int fd[2]; | ||
176 | }; | ||
177 | |||
173 | struct audit_aux_data_path { | 178 | struct audit_aux_data_path { |
174 | struct audit_aux_data d; | 179 | struct audit_aux_data d; |
175 | struct dentry *dentry; | 180 | struct dentry *dentry; |
@@ -961,6 +966,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
961 | audit_log_d_path(ab, "path=", axi->dentry, axi->mnt); | 966 | audit_log_d_path(ab, "path=", axi->dentry, axi->mnt); |
962 | break; } | 967 | break; } |
963 | 968 | ||
969 | case AUDIT_FD_PAIR: { | ||
970 | struct audit_aux_data_fd_pair *axs = (void *)aux; | ||
971 | audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]); | ||
972 | break; } | ||
973 | |||
964 | } | 974 | } |
965 | audit_log_end(ab); | 975 | audit_log_end(ab); |
966 | } | 976 | } |
@@ -1815,6 +1825,36 @@ int audit_socketcall(int nargs, unsigned long *args) | |||
1815 | } | 1825 | } |
1816 | 1826 | ||
1817 | /** | 1827 | /** |
1828 | * __audit_fd_pair - record audit data for pipe and socketpair | ||
1829 | * @fd1: the first file descriptor | ||
1830 | * @fd2: the second file descriptor | ||
1831 | * | ||
1832 | * Returns 0 for success or NULL context or < 0 on error. | ||
1833 | */ | ||
1834 | int __audit_fd_pair(int fd1, int fd2) | ||
1835 | { | ||
1836 | struct audit_context *context = current->audit_context; | ||
1837 | struct audit_aux_data_fd_pair *ax; | ||
1838 | |||
1839 | if (likely(!context)) { | ||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1843 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); | ||
1844 | if (!ax) { | ||
1845 | return -ENOMEM; | ||
1846 | } | ||
1847 | |||
1848 | ax->fd[0] = fd1; | ||
1849 | ax->fd[1] = fd2; | ||
1850 | |||
1851 | ax->d.type = AUDIT_FD_PAIR; | ||
1852 | ax->d.next = context->aux; | ||
1853 | context->aux = (void *)ax; | ||
1854 | return 0; | ||
1855 | } | ||
1856 | |||
1857 | /** | ||
1818 | * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto | 1858 | * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto |
1819 | * @len: data length in user space | 1859 | * @len: data length in user space |
1820 | * @a: data address in kernel space | 1860 | * @a: data address in kernel space |
diff --git a/kernel/kmod.c b/kernel/kmod.c index 796276141e51..9f923f8ce6a0 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/resource.h> | 36 | #include <linux/resource.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | 38 | ||
39 | extern int delete_module(const char *name, unsigned int flags); | ||
40 | |||
39 | extern int max_threads; | 41 | extern int max_threads; |
40 | 42 | ||
41 | static struct workqueue_struct *khelper_wq; | 43 | static struct workqueue_struct *khelper_wq; |
@@ -46,6 +48,7 @@ static struct workqueue_struct *khelper_wq; | |||
46 | modprobe_path is set via /proc/sys. | 48 | modprobe_path is set via /proc/sys. |
47 | */ | 49 | */ |
48 | char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; | 50 | char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; |
51 | struct module_kobject kmod_mk; | ||
49 | 52 | ||
50 | /** | 53 | /** |
51 | * request_module - try to load a kernel module | 54 | * request_module - try to load a kernel module |
@@ -75,6 +78,11 @@ int request_module(const char *fmt, ...) | |||
75 | static atomic_t kmod_concurrent = ATOMIC_INIT(0); | 78 | static atomic_t kmod_concurrent = ATOMIC_INIT(0); |
76 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ | 79 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ |
77 | static int kmod_loop_msg; | 80 | static int kmod_loop_msg; |
81 | char modalias[16 + MODULE_NAME_LEN] = "MODALIAS="; | ||
82 | char *uevent_envp[2] = { | ||
83 | modalias, | ||
84 | NULL | ||
85 | }; | ||
78 | 86 | ||
79 | va_start(args, fmt); | 87 | va_start(args, fmt); |
80 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); | 88 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); |
@@ -82,6 +90,12 @@ int request_module(const char *fmt, ...) | |||
82 | if (ret >= MODULE_NAME_LEN) | 90 | if (ret >= MODULE_NAME_LEN) |
83 | return -ENAMETOOLONG; | 91 | return -ENAMETOOLONG; |
84 | 92 | ||
93 | strcpy(&modalias[strlen("MODALIAS=")], module_name); | ||
94 | kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp); | ||
95 | |||
96 | if (modprobe_path[0] == '\0') | ||
97 | goto out; | ||
98 | |||
85 | /* If modprobe needs a service that is in a module, we get a recursive | 99 | /* If modprobe needs a service that is in a module, we get a recursive |
86 | * loop. Limit the number of running kmod threads to max_threads/2 or | 100 | * loop. Limit the number of running kmod threads to max_threads/2 or |
87 | * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method | 101 | * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method |
@@ -108,9 +122,115 @@ int request_module(const char *fmt, ...) | |||
108 | 122 | ||
109 | ret = call_usermodehelper(modprobe_path, argv, envp, 1); | 123 | ret = call_usermodehelper(modprobe_path, argv, envp, 1); |
110 | atomic_dec(&kmod_concurrent); | 124 | atomic_dec(&kmod_concurrent); |
125 | out: | ||
111 | return ret; | 126 | return ret; |
112 | } | 127 | } |
113 | EXPORT_SYMBOL(request_module); | 128 | EXPORT_SYMBOL(request_module); |
129 | |||
130 | static ssize_t store_mod_request(struct module_attribute *mattr, | ||
131 | struct module *mod, | ||
132 | const char *buffer, size_t count) | ||
133 | { | ||
134 | char name[MODULE_NAME_LEN]; | ||
135 | int ret; | ||
136 | |||
137 | if (count < 1 || count+1 > MODULE_NAME_LEN) | ||
138 | return -EINVAL; | ||
139 | memcpy(name, buffer, count); | ||
140 | name[count] = '\0'; | ||
141 | if (name[count-1] == '\n') | ||
142 | name[count-1] = '\0'; | ||
143 | |||
144 | ret = request_module(name); | ||
145 | if (ret < 0) | ||
146 | return ret; | ||
147 | return count; | ||
148 | } | ||
149 | |||
150 | static struct module_attribute mod_request = { | ||
151 | .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE }, | ||
152 | .store = store_mod_request, | ||
153 | }; | ||
154 | |||
155 | #ifdef CONFIG_MODULE_UNLOAD | ||
156 | static ssize_t store_mod_unload(struct module_attribute *mattr, | ||
157 | struct module *mod, | ||
158 | const char *buffer, size_t count) | ||
159 | { | ||
160 | char name[MODULE_NAME_LEN]; | ||
161 | int ret; | ||
162 | |||
163 | if (count < 1 || count+1 > MODULE_NAME_LEN) | ||
164 | return -EINVAL; | ||
165 | memcpy(name, buffer, count); | ||
166 | name[count] = '\0'; | ||
167 | if (name[count-1] == '\n') | ||
168 | name[count-1] = '\0'; | ||
169 | |||
170 | ret = delete_module(name, O_NONBLOCK); | ||
171 | if (ret < 0) | ||
172 | return ret; | ||
173 | return count; | ||
174 | } | ||
175 | |||
176 | static struct module_attribute mod_unload = { | ||
177 | .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE }, | ||
178 | .store = store_mod_unload, | ||
179 | }; | ||
180 | #endif | ||
181 | |||
182 | static ssize_t show_mod_request_helper(struct module_attribute *mattr, | ||
183 | struct module *mod, | ||
184 | char *buffer) | ||
185 | { | ||
186 | return sprintf(buffer, "%s\n", modprobe_path); | ||
187 | } | ||
188 | |||
189 | static ssize_t store_mod_request_helper(struct module_attribute *mattr, | ||
190 | struct module *mod, | ||
191 | const char *buffer, size_t count) | ||
192 | { | ||
193 | if (count < 1 || count+1 > KMOD_PATH_LEN) | ||
194 | return -EINVAL; | ||
195 | memcpy(modprobe_path, buffer, count); | ||
196 | modprobe_path[count] = '\0'; | ||
197 | if (modprobe_path[count-1] == '\n') | ||
198 | modprobe_path[count-1] = '\0'; | ||
199 | return count; | ||
200 | } | ||
201 | |||
202 | static struct module_attribute mod_request_helper = { | ||
203 | .attr = { | ||
204 | .name = "mod_request_helper", | ||
205 | .mode = S_IWUSR | S_IRUGO, | ||
206 | .owner = THIS_MODULE | ||
207 | }, | ||
208 | .show = show_mod_request_helper, | ||
209 | .store = store_mod_request_helper, | ||
210 | }; | ||
211 | |||
212 | void __init kmod_sysfs_init(void) | ||
213 | { | ||
214 | int ret; | ||
215 | |||
216 | kmod_mk.mod = THIS_MODULE; | ||
217 | kobj_set_kset_s(&kmod_mk, module_subsys); | ||
218 | kobject_set_name(&kmod_mk.kobj, "kmod"); | ||
219 | kobject_init(&kmod_mk.kobj); | ||
220 | ret = kobject_add(&kmod_mk.kobj); | ||
221 | if (ret < 0) | ||
222 | goto out; | ||
223 | |||
224 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr); | ||
225 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr); | ||
226 | #ifdef CONFIG_MODULE_UNLOAD | ||
227 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr); | ||
228 | #endif | ||
229 | |||
230 | kobject_uevent(&kmod_mk.kobj, KOBJ_ADD); | ||
231 | out: | ||
232 | return; | ||
233 | } | ||
114 | #endif /* CONFIG_KMOD */ | 234 | #endif /* CONFIG_KMOD */ |
115 | 235 | ||
116 | struct subprocess_info { | 236 | struct subprocess_info { |
diff --git a/kernel/module.c b/kernel/module.c index 8a94e054230c..8c25b1a04fa6 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -653,20 +653,11 @@ static void wait_for_zero_refcount(struct module *mod) | |||
653 | mutex_lock(&module_mutex); | 653 | mutex_lock(&module_mutex); |
654 | } | 654 | } |
655 | 655 | ||
656 | asmlinkage long | 656 | int delete_module(const char *name, unsigned int flags) |
657 | sys_delete_module(const char __user *name_user, unsigned int flags) | ||
658 | { | 657 | { |
659 | struct module *mod; | 658 | struct module *mod; |
660 | char name[MODULE_NAME_LEN]; | ||
661 | int ret, forced = 0; | 659 | int ret, forced = 0; |
662 | 660 | ||
663 | if (!capable(CAP_SYS_MODULE)) | ||
664 | return -EPERM; | ||
665 | |||
666 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) | ||
667 | return -EFAULT; | ||
668 | name[MODULE_NAME_LEN-1] = '\0'; | ||
669 | |||
670 | if (mutex_lock_interruptible(&module_mutex) != 0) | 661 | if (mutex_lock_interruptible(&module_mutex) != 0) |
671 | return -EINTR; | 662 | return -EINTR; |
672 | 663 | ||
@@ -727,6 +718,21 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
727 | return ret; | 718 | return ret; |
728 | } | 719 | } |
729 | 720 | ||
721 | asmlinkage long | ||
722 | sys_delete_module(const char __user *name_user, unsigned int flags) | ||
723 | { | ||
724 | char name[MODULE_NAME_LEN]; | ||
725 | |||
726 | if (!capable(CAP_SYS_MODULE)) | ||
727 | return -EPERM; | ||
728 | |||
729 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) | ||
730 | return -EFAULT; | ||
731 | name[MODULE_NAME_LEN-1] = '\0'; | ||
732 | |||
733 | return delete_module(name, flags); | ||
734 | } | ||
735 | |||
730 | static void print_unload_info(struct seq_file *m, struct module *mod) | 736 | static void print_unload_info(struct seq_file *m, struct module *mod) |
731 | { | 737 | { |
732 | struct module_use *use; | 738 | struct module_use *use; |
@@ -1068,7 +1074,8 @@ static inline void remove_sect_attrs(struct module *mod) | |||
1068 | } | 1074 | } |
1069 | #endif /* CONFIG_KALLSYMS */ | 1075 | #endif /* CONFIG_KALLSYMS */ |
1070 | 1076 | ||
1071 | static int module_add_modinfo_attrs(struct module *mod) | 1077 | #ifdef CONFIG_SYSFS |
1078 | int module_add_modinfo_attrs(struct module *mod) | ||
1072 | { | 1079 | { |
1073 | struct module_attribute *attr; | 1080 | struct module_attribute *attr; |
1074 | struct module_attribute *temp_attr; | 1081 | struct module_attribute *temp_attr; |
@@ -1094,7 +1101,7 @@ static int module_add_modinfo_attrs(struct module *mod) | |||
1094 | return error; | 1101 | return error; |
1095 | } | 1102 | } |
1096 | 1103 | ||
1097 | static void module_remove_modinfo_attrs(struct module *mod) | 1104 | void module_remove_modinfo_attrs(struct module *mod) |
1098 | { | 1105 | { |
1099 | struct module_attribute *attr; | 1106 | struct module_attribute *attr; |
1100 | int i; | 1107 | int i; |
@@ -1109,8 +1116,10 @@ static void module_remove_modinfo_attrs(struct module *mod) | |||
1109 | } | 1116 | } |
1110 | kfree(mod->modinfo_attrs); | 1117 | kfree(mod->modinfo_attrs); |
1111 | } | 1118 | } |
1119 | #endif | ||
1112 | 1120 | ||
1113 | static int mod_sysfs_init(struct module *mod) | 1121 | #ifdef CONFIG_SYSFS |
1122 | int mod_sysfs_init(struct module *mod) | ||
1114 | { | 1123 | { |
1115 | int err; | 1124 | int err; |
1116 | 1125 | ||
@@ -1133,7 +1142,7 @@ out: | |||
1133 | return err; | 1142 | return err; |
1134 | } | 1143 | } |
1135 | 1144 | ||
1136 | static int mod_sysfs_setup(struct module *mod, | 1145 | int mod_sysfs_setup(struct module *mod, |
1137 | struct kernel_param *kparam, | 1146 | struct kernel_param *kparam, |
1138 | unsigned int num_params) | 1147 | unsigned int num_params) |
1139 | { | 1148 | { |
@@ -1169,16 +1178,14 @@ out_unreg: | |||
1169 | out: | 1178 | out: |
1170 | return err; | 1179 | return err; |
1171 | } | 1180 | } |
1181 | #endif | ||
1172 | 1182 | ||
1173 | static void mod_kobject_remove(struct module *mod) | 1183 | static void mod_kobject_remove(struct module *mod) |
1174 | { | 1184 | { |
1175 | module_remove_modinfo_attrs(mod); | 1185 | module_remove_modinfo_attrs(mod); |
1176 | module_param_sysfs_remove(mod); | 1186 | module_param_sysfs_remove(mod); |
1177 | if (mod->mkobj.drivers_dir) | 1187 | kobject_unregister(mod->mkobj.drivers_dir); |
1178 | kobject_unregister(mod->mkobj.drivers_dir); | 1188 | kobject_unregister(mod->holders_dir); |
1179 | if (mod->holders_dir) | ||
1180 | kobject_unregister(mod->holders_dir); | ||
1181 | |||
1182 | kobject_unregister(&mod->mkobj.kobj); | 1189 | kobject_unregister(&mod->mkobj.kobj); |
1183 | } | 1190 | } |
1184 | 1191 | ||
@@ -2345,6 +2352,7 @@ void print_modules(void) | |||
2345 | printk("\n"); | 2352 | printk("\n"); |
2346 | } | 2353 | } |
2347 | 2354 | ||
2355 | #ifdef CONFIG_SYSFS | ||
2348 | static char *make_driver_name(struct device_driver *drv) | 2356 | static char *make_driver_name(struct device_driver *drv) |
2349 | { | 2357 | { |
2350 | char *driver_name; | 2358 | char *driver_name; |
@@ -2419,6 +2427,7 @@ void module_remove_driver(struct device_driver *drv) | |||
2419 | } | 2427 | } |
2420 | } | 2428 | } |
2421 | EXPORT_SYMBOL(module_remove_driver); | 2429 | EXPORT_SYMBOL(module_remove_driver); |
2430 | #endif | ||
2422 | 2431 | ||
2423 | #ifdef CONFIG_MODVERSIONS | 2432 | #ifdef CONFIG_MODVERSIONS |
2424 | /* Generate the signature for struct module here, too, for modversions. */ | 2433 | /* Generate the signature for struct module here, too, for modversions. */ |
diff --git a/kernel/params.c b/kernel/params.c index 553cf7d6a4be..7a751570b56d 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -30,8 +30,6 @@ | |||
30 | #define DEBUGP(fmt, a...) | 30 | #define DEBUGP(fmt, a...) |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | static struct kobj_type module_ktype; | ||
34 | |||
35 | static inline char dash2underscore(char c) | 33 | static inline char dash2underscore(char c) |
36 | { | 34 | { |
37 | if (c == '-') | 35 | if (c == '-') |
@@ -391,6 +389,7 @@ struct module_param_attrs | |||
391 | struct param_attribute attrs[0]; | 389 | struct param_attribute attrs[0]; |
392 | }; | 390 | }; |
393 | 391 | ||
392 | #ifdef CONFIG_SYSFS | ||
394 | #define to_param_attr(n) container_of(n, struct param_attribute, mattr); | 393 | #define to_param_attr(n) container_of(n, struct param_attribute, mattr); |
395 | 394 | ||
396 | static ssize_t param_attr_show(struct module_attribute *mattr, | 395 | static ssize_t param_attr_show(struct module_attribute *mattr, |
@@ -426,6 +425,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
426 | return len; | 425 | return len; |
427 | return err; | 426 | return err; |
428 | } | 427 | } |
428 | #endif | ||
429 | 429 | ||
430 | #ifdef CONFIG_MODULES | 430 | #ifdef CONFIG_MODULES |
431 | #define __modinit | 431 | #define __modinit |
@@ -433,6 +433,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
433 | #define __modinit __init | 433 | #define __modinit __init |
434 | #endif | 434 | #endif |
435 | 435 | ||
436 | #ifdef CONFIG_SYSFS | ||
436 | /* | 437 | /* |
437 | * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME | 438 | * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME |
438 | * @mk: struct module_kobject (contains parent kobject) | 439 | * @mk: struct module_kobject (contains parent kobject) |
@@ -500,9 +501,7 @@ param_sysfs_setup(struct module_kobject *mk, | |||
500 | return mp; | 501 | return mp; |
501 | } | 502 | } |
502 | 503 | ||
503 | |||
504 | #ifdef CONFIG_MODULES | 504 | #ifdef CONFIG_MODULES |
505 | |||
506 | /* | 505 | /* |
507 | * module_param_sysfs_setup - setup sysfs support for one module | 506 | * module_param_sysfs_setup - setup sysfs support for one module |
508 | * @mod: module | 507 | * @mod: module |
@@ -625,7 +624,6 @@ static void __init param_sysfs_builtin(void) | |||
625 | 624 | ||
626 | 625 | ||
627 | /* module-related sysfs stuff */ | 626 | /* module-related sysfs stuff */ |
628 | #ifdef CONFIG_SYSFS | ||
629 | 627 | ||
630 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); | 628 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); |
631 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); | 629 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); |
@@ -673,6 +671,8 @@ static struct sysfs_ops module_sysfs_ops = { | |||
673 | .store = module_attr_store, | 671 | .store = module_attr_store, |
674 | }; | 672 | }; |
675 | 673 | ||
674 | static struct kobj_type module_ktype; | ||
675 | |||
676 | static int uevent_filter(struct kset *kset, struct kobject *kobj) | 676 | static int uevent_filter(struct kset *kset, struct kobject *kobj) |
677 | { | 677 | { |
678 | struct kobj_type *ktype = get_ktype(kobj); | 678 | struct kobj_type *ktype = get_ktype(kobj); |
@@ -686,19 +686,12 @@ static struct kset_uevent_ops module_uevent_ops = { | |||
686 | .filter = uevent_filter, | 686 | .filter = uevent_filter, |
687 | }; | 687 | }; |
688 | 688 | ||
689 | #else | 689 | decl_subsys(module, &module_ktype, &module_uevent_ops); |
690 | static struct sysfs_ops module_sysfs_ops = { | ||
691 | .show = NULL, | ||
692 | .store = NULL, | ||
693 | }; | ||
694 | #endif | ||
695 | 690 | ||
696 | static struct kobj_type module_ktype = { | 691 | static struct kobj_type module_ktype = { |
697 | .sysfs_ops = &module_sysfs_ops, | 692 | .sysfs_ops = &module_sysfs_ops, |
698 | }; | 693 | }; |
699 | 694 | ||
700 | decl_subsys(module, &module_ktype, &module_uevent_ops); | ||
701 | |||
702 | /* | 695 | /* |
703 | * param_sysfs_init - wrapper for built-in params support | 696 | * param_sysfs_init - wrapper for built-in params support |
704 | */ | 697 | */ |
@@ -714,11 +707,21 @@ static int __init param_sysfs_init(void) | |||
714 | } | 707 | } |
715 | 708 | ||
716 | param_sysfs_builtin(); | 709 | param_sysfs_builtin(); |
710 | kmod_sysfs_init(); | ||
717 | 711 | ||
718 | return 0; | 712 | return 0; |
719 | } | 713 | } |
720 | subsys_initcall(param_sysfs_init); | 714 | subsys_initcall(param_sysfs_init); |
721 | 715 | ||
716 | #else | ||
717 | #if 0 | ||
718 | static struct sysfs_ops module_sysfs_ops = { | ||
719 | .show = NULL, | ||
720 | .store = NULL, | ||
721 | }; | ||
722 | #endif | ||
723 | #endif | ||
724 | |||
722 | EXPORT_SYMBOL(param_set_byte); | 725 | EXPORT_SYMBOL(param_set_byte); |
723 | EXPORT_SYMBOL(param_get_byte); | 726 | EXPORT_SYMBOL(param_get_byte); |
724 | EXPORT_SYMBOL(param_set_short); | 727 | EXPORT_SYMBOL(param_set_short); |
diff --git a/kernel/printk.c b/kernel/printk.c index 0c151877ff71..4b47e59248df 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -54,7 +54,7 @@ int console_printk[4] = { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Low lever drivers may need that to know if they can schedule in | 57 | * Low level drivers may need that to know if they can schedule in |
58 | * their unblank() callback or not. So let's export it. | 58 | * their unblank() callback or not. So let's export it. |
59 | */ | 59 | */ |
60 | int oops_in_progress; | 60 | int oops_in_progress; |