diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 154 |
1 files changed, 89 insertions, 65 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 53d9a9ec88e6..36231525e22f 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -97,7 +97,7 @@ static int console_locked, console_suspended; | |||
97 | /* | 97 | /* |
98 | * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars | 98 | * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars |
99 | * It is also used in interesting ways to provide interlocking in | 99 | * It is also used in interesting ways to provide interlocking in |
100 | * release_console_sem(). | 100 | * console_unlock();. |
101 | */ | 101 | */ |
102 | static DEFINE_SPINLOCK(logbuf_lock); | 102 | static DEFINE_SPINLOCK(logbuf_lock); |
103 | 103 | ||
@@ -262,25 +262,47 @@ int dmesg_restrict = 1; | |||
262 | int dmesg_restrict; | 262 | int dmesg_restrict; |
263 | #endif | 263 | #endif |
264 | 264 | ||
265 | static int syslog_action_restricted(int type) | ||
266 | { | ||
267 | if (dmesg_restrict) | ||
268 | return 1; | ||
269 | /* Unless restricted, we allow "read all" and "get buffer size" for everybody */ | ||
270 | return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER; | ||
271 | } | ||
272 | |||
273 | static int check_syslog_permissions(int type, bool from_file) | ||
274 | { | ||
275 | /* | ||
276 | * If this is from /proc/kmsg and we've already opened it, then we've | ||
277 | * already done the capabilities checks at open time. | ||
278 | */ | ||
279 | if (from_file && type != SYSLOG_ACTION_OPEN) | ||
280 | return 0; | ||
281 | |||
282 | if (syslog_action_restricted(type)) { | ||
283 | if (capable(CAP_SYSLOG)) | ||
284 | return 0; | ||
285 | /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ | ||
286 | if (capable(CAP_SYS_ADMIN)) { | ||
287 | WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN " | ||
288 | "but no CAP_SYSLOG (deprecated).\n"); | ||
289 | return 0; | ||
290 | } | ||
291 | return -EPERM; | ||
292 | } | ||
293 | return 0; | ||
294 | } | ||
295 | |||
265 | int do_syslog(int type, char __user *buf, int len, bool from_file) | 296 | int do_syslog(int type, char __user *buf, int len, bool from_file) |
266 | { | 297 | { |
267 | unsigned i, j, limit, count; | 298 | unsigned i, j, limit, count; |
268 | int do_clear = 0; | 299 | int do_clear = 0; |
269 | char c; | 300 | char c; |
270 | int error = 0; | 301 | int error; |
271 | 302 | ||
272 | /* | 303 | error = check_syslog_permissions(type, from_file); |
273 | * If this is from /proc/kmsg we only do the capabilities checks | 304 | if (error) |
274 | * at open time. | 305 | goto out; |
275 | */ | ||
276 | if (type == SYSLOG_ACTION_OPEN || !from_file) { | ||
277 | if (dmesg_restrict && !capable(CAP_SYSLOG)) | ||
278 | goto warn; /* switch to return -EPERM after 2.6.39 */ | ||
279 | if ((type != SYSLOG_ACTION_READ_ALL && | ||
280 | type != SYSLOG_ACTION_SIZE_BUFFER) && | ||
281 | !capable(CAP_SYSLOG)) | ||
282 | goto warn; /* switch to return -EPERM after 2.6.39 */ | ||
283 | } | ||
284 | 306 | ||
285 | error = security_syslog(type); | 307 | error = security_syslog(type); |
286 | if (error) | 308 | if (error) |
@@ -423,12 +445,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
423 | } | 445 | } |
424 | out: | 446 | out: |
425 | return error; | 447 | return error; |
426 | warn: | ||
427 | /* remove after 2.6.39 */ | ||
428 | if (capable(CAP_SYS_ADMIN)) | ||
429 | WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN " | ||
430 | "but no CAP_SYSLOG (deprecated and denied).\n"); | ||
431 | return -EPERM; | ||
432 | } | 448 | } |
433 | 449 | ||
434 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | 450 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) |
@@ -501,7 +517,7 @@ static void _call_console_drivers(unsigned start, | |||
501 | /* | 517 | /* |
502 | * Call the console drivers, asking them to write out | 518 | * Call the console drivers, asking them to write out |
503 | * log_buf[start] to log_buf[end - 1]. | 519 | * log_buf[start] to log_buf[end - 1]. |
504 | * The console_sem must be held. | 520 | * The console_lock must be held. |
505 | */ | 521 | */ |
506 | static void call_console_drivers(unsigned start, unsigned end) | 522 | static void call_console_drivers(unsigned start, unsigned end) |
507 | { | 523 | { |
@@ -604,11 +620,11 @@ static int have_callable_console(void) | |||
604 | * | 620 | * |
605 | * This is printk(). It can be called from any context. We want it to work. | 621 | * This is printk(). It can be called from any context. We want it to work. |
606 | * | 622 | * |
607 | * We try to grab the console_sem. If we succeed, it's easy - we log the output and | 623 | * We try to grab the console_lock. If we succeed, it's easy - we log the output and |
608 | * call the console drivers. If we fail to get the semaphore we place the output | 624 | * call the console drivers. If we fail to get the semaphore we place the output |
609 | * into the log buffer and return. The current holder of the console_sem will | 625 | * into the log buffer and return. The current holder of the console_sem will |
610 | * notice the new output in release_console_sem() and will send it to the | 626 | * notice the new output in console_unlock(); and will send it to the |
611 | * consoles before releasing the semaphore. | 627 | * consoles before releasing the lock. |
612 | * | 628 | * |
613 | * One effect of this deferred printing is that code which calls printk() and | 629 | * One effect of this deferred printing is that code which calls printk() and |
614 | * then changes console_loglevel may break. This is because console_loglevel | 630 | * then changes console_loglevel may break. This is because console_loglevel |
@@ -659,19 +675,19 @@ static inline int can_use_console(unsigned int cpu) | |||
659 | /* | 675 | /* |
660 | * Try to get console ownership to actually show the kernel | 676 | * Try to get console ownership to actually show the kernel |
661 | * messages from a 'printk'. Return true (and with the | 677 | * messages from a 'printk'. Return true (and with the |
662 | * console_semaphore held, and 'console_locked' set) if it | 678 | * console_lock held, and 'console_locked' set) if it |
663 | * is successful, false otherwise. | 679 | * is successful, false otherwise. |
664 | * | 680 | * |
665 | * This gets called with the 'logbuf_lock' spinlock held and | 681 | * This gets called with the 'logbuf_lock' spinlock held and |
666 | * interrupts disabled. It should return with 'lockbuf_lock' | 682 | * interrupts disabled. It should return with 'lockbuf_lock' |
667 | * released but interrupts still disabled. | 683 | * released but interrupts still disabled. |
668 | */ | 684 | */ |
669 | static int acquire_console_semaphore_for_printk(unsigned int cpu) | 685 | static int console_trylock_for_printk(unsigned int cpu) |
670 | __releases(&logbuf_lock) | 686 | __releases(&logbuf_lock) |
671 | { | 687 | { |
672 | int retval = 0; | 688 | int retval = 0; |
673 | 689 | ||
674 | if (!try_acquire_console_sem()) { | 690 | if (console_trylock()) { |
675 | retval = 1; | 691 | retval = 1; |
676 | 692 | ||
677 | /* | 693 | /* |
@@ -827,12 +843,12 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
827 | * actual magic (print out buffers, wake up klogd, | 843 | * actual magic (print out buffers, wake up klogd, |
828 | * etc). | 844 | * etc). |
829 | * | 845 | * |
830 | * The acquire_console_semaphore_for_printk() function | 846 | * The console_trylock_for_printk() function |
831 | * will release 'logbuf_lock' regardless of whether it | 847 | * will release 'logbuf_lock' regardless of whether it |
832 | * actually gets the semaphore or not. | 848 | * actually gets the semaphore or not. |
833 | */ | 849 | */ |
834 | if (acquire_console_semaphore_for_printk(this_cpu)) | 850 | if (console_trylock_for_printk(this_cpu)) |
835 | release_console_sem(); | 851 | console_unlock(); |
836 | 852 | ||
837 | lockdep_on(); | 853 | lockdep_on(); |
838 | out_restore_irqs: | 854 | out_restore_irqs: |
@@ -993,7 +1009,7 @@ void suspend_console(void) | |||
993 | if (!console_suspend_enabled) | 1009 | if (!console_suspend_enabled) |
994 | return; | 1010 | return; |
995 | printk("Suspending console(s) (use no_console_suspend to debug)\n"); | 1011 | printk("Suspending console(s) (use no_console_suspend to debug)\n"); |
996 | acquire_console_sem(); | 1012 | console_lock(); |
997 | console_suspended = 1; | 1013 | console_suspended = 1; |
998 | up(&console_sem); | 1014 | up(&console_sem); |
999 | } | 1015 | } |
@@ -1004,7 +1020,7 @@ void resume_console(void) | |||
1004 | return; | 1020 | return; |
1005 | down(&console_sem); | 1021 | down(&console_sem); |
1006 | console_suspended = 0; | 1022 | console_suspended = 0; |
1007 | release_console_sem(); | 1023 | console_unlock(); |
1008 | } | 1024 | } |
1009 | 1025 | ||
1010 | /** | 1026 | /** |
@@ -1027,21 +1043,21 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self, | |||
1027 | case CPU_DYING: | 1043 | case CPU_DYING: |
1028 | case CPU_DOWN_FAILED: | 1044 | case CPU_DOWN_FAILED: |
1029 | case CPU_UP_CANCELED: | 1045 | case CPU_UP_CANCELED: |
1030 | acquire_console_sem(); | 1046 | console_lock(); |
1031 | release_console_sem(); | 1047 | console_unlock(); |
1032 | } | 1048 | } |
1033 | return NOTIFY_OK; | 1049 | return NOTIFY_OK; |
1034 | } | 1050 | } |
1035 | 1051 | ||
1036 | /** | 1052 | /** |
1037 | * acquire_console_sem - lock the console system for exclusive use. | 1053 | * console_lock - lock the console system for exclusive use. |
1038 | * | 1054 | * |
1039 | * Acquires a semaphore which guarantees that the caller has | 1055 | * Acquires a lock which guarantees that the caller has |
1040 | * exclusive access to the console system and the console_drivers list. | 1056 | * exclusive access to the console system and the console_drivers list. |
1041 | * | 1057 | * |
1042 | * Can sleep, returns nothing. | 1058 | * Can sleep, returns nothing. |
1043 | */ | 1059 | */ |
1044 | void acquire_console_sem(void) | 1060 | void console_lock(void) |
1045 | { | 1061 | { |
1046 | BUG_ON(in_interrupt()); | 1062 | BUG_ON(in_interrupt()); |
1047 | down(&console_sem); | 1063 | down(&console_sem); |
@@ -1050,21 +1066,29 @@ void acquire_console_sem(void) | |||
1050 | console_locked = 1; | 1066 | console_locked = 1; |
1051 | console_may_schedule = 1; | 1067 | console_may_schedule = 1; |
1052 | } | 1068 | } |
1053 | EXPORT_SYMBOL(acquire_console_sem); | 1069 | EXPORT_SYMBOL(console_lock); |
1054 | 1070 | ||
1055 | int try_acquire_console_sem(void) | 1071 | /** |
1072 | * console_trylock - try to lock the console system for exclusive use. | ||
1073 | * | ||
1074 | * Tried to acquire a lock which guarantees that the caller has | ||
1075 | * exclusive access to the console system and the console_drivers list. | ||
1076 | * | ||
1077 | * returns 1 on success, and 0 on failure to acquire the lock. | ||
1078 | */ | ||
1079 | int console_trylock(void) | ||
1056 | { | 1080 | { |
1057 | if (down_trylock(&console_sem)) | 1081 | if (down_trylock(&console_sem)) |
1058 | return -1; | 1082 | return 0; |
1059 | if (console_suspended) { | 1083 | if (console_suspended) { |
1060 | up(&console_sem); | 1084 | up(&console_sem); |
1061 | return -1; | 1085 | return 0; |
1062 | } | 1086 | } |
1063 | console_locked = 1; | 1087 | console_locked = 1; |
1064 | console_may_schedule = 0; | 1088 | console_may_schedule = 0; |
1065 | return 0; | 1089 | return 1; |
1066 | } | 1090 | } |
1067 | EXPORT_SYMBOL(try_acquire_console_sem); | 1091 | EXPORT_SYMBOL(console_trylock); |
1068 | 1092 | ||
1069 | int is_console_locked(void) | 1093 | int is_console_locked(void) |
1070 | { | 1094 | { |
@@ -1095,20 +1119,20 @@ void wake_up_klogd(void) | |||
1095 | } | 1119 | } |
1096 | 1120 | ||
1097 | /** | 1121 | /** |
1098 | * release_console_sem - unlock the console system | 1122 | * console_unlock - unlock the console system |
1099 | * | 1123 | * |
1100 | * Releases the semaphore which the caller holds on the console system | 1124 | * Releases the console_lock which the caller holds on the console system |
1101 | * and the console driver list. | 1125 | * and the console driver list. |
1102 | * | 1126 | * |
1103 | * While the semaphore was held, console output may have been buffered | 1127 | * While the console_lock was held, console output may have been buffered |
1104 | * by printk(). If this is the case, release_console_sem() emits | 1128 | * by printk(). If this is the case, console_unlock(); emits |
1105 | * the output prior to releasing the semaphore. | 1129 | * the output prior to releasing the lock. |
1106 | * | 1130 | * |
1107 | * If there is output waiting for klogd, we wake it up. | 1131 | * If there is output waiting for klogd, we wake it up. |
1108 | * | 1132 | * |
1109 | * release_console_sem() may be called from any context. | 1133 | * console_unlock(); may be called from any context. |
1110 | */ | 1134 | */ |
1111 | void release_console_sem(void) | 1135 | void console_unlock(void) |
1112 | { | 1136 | { |
1113 | unsigned long flags; | 1137 | unsigned long flags; |
1114 | unsigned _con_start, _log_end; | 1138 | unsigned _con_start, _log_end; |
@@ -1141,7 +1165,7 @@ void release_console_sem(void) | |||
1141 | if (wake_klogd) | 1165 | if (wake_klogd) |
1142 | wake_up_klogd(); | 1166 | wake_up_klogd(); |
1143 | } | 1167 | } |
1144 | EXPORT_SYMBOL(release_console_sem); | 1168 | EXPORT_SYMBOL(console_unlock); |
1145 | 1169 | ||
1146 | /** | 1170 | /** |
1147 | * console_conditional_schedule - yield the CPU if required | 1171 | * console_conditional_schedule - yield the CPU if required |
@@ -1150,7 +1174,7 @@ EXPORT_SYMBOL(release_console_sem); | |||
1150 | * if this CPU should yield the CPU to another task, do | 1174 | * if this CPU should yield the CPU to another task, do |
1151 | * so here. | 1175 | * so here. |
1152 | * | 1176 | * |
1153 | * Must be called within acquire_console_sem(). | 1177 | * Must be called within console_lock();. |
1154 | */ | 1178 | */ |
1155 | void __sched console_conditional_schedule(void) | 1179 | void __sched console_conditional_schedule(void) |
1156 | { | 1180 | { |
@@ -1171,14 +1195,14 @@ void console_unblank(void) | |||
1171 | if (down_trylock(&console_sem) != 0) | 1195 | if (down_trylock(&console_sem) != 0) |
1172 | return; | 1196 | return; |
1173 | } else | 1197 | } else |
1174 | acquire_console_sem(); | 1198 | console_lock(); |
1175 | 1199 | ||
1176 | console_locked = 1; | 1200 | console_locked = 1; |
1177 | console_may_schedule = 0; | 1201 | console_may_schedule = 0; |
1178 | for_each_console(c) | 1202 | for_each_console(c) |
1179 | if ((c->flags & CON_ENABLED) && c->unblank) | 1203 | if ((c->flags & CON_ENABLED) && c->unblank) |
1180 | c->unblank(); | 1204 | c->unblank(); |
1181 | release_console_sem(); | 1205 | console_unlock(); |
1182 | } | 1206 | } |
1183 | 1207 | ||
1184 | /* | 1208 | /* |
@@ -1189,7 +1213,7 @@ struct tty_driver *console_device(int *index) | |||
1189 | struct console *c; | 1213 | struct console *c; |
1190 | struct tty_driver *driver = NULL; | 1214 | struct tty_driver *driver = NULL; |
1191 | 1215 | ||
1192 | acquire_console_sem(); | 1216 | console_lock(); |
1193 | for_each_console(c) { | 1217 | for_each_console(c) { |
1194 | if (!c->device) | 1218 | if (!c->device) |
1195 | continue; | 1219 | continue; |
@@ -1197,7 +1221,7 @@ struct tty_driver *console_device(int *index) | |||
1197 | if (driver) | 1221 | if (driver) |
1198 | break; | 1222 | break; |
1199 | } | 1223 | } |
1200 | release_console_sem(); | 1224 | console_unlock(); |
1201 | return driver; | 1225 | return driver; |
1202 | } | 1226 | } |
1203 | 1227 | ||
@@ -1208,17 +1232,17 @@ struct tty_driver *console_device(int *index) | |||
1208 | */ | 1232 | */ |
1209 | void console_stop(struct console *console) | 1233 | void console_stop(struct console *console) |
1210 | { | 1234 | { |
1211 | acquire_console_sem(); | 1235 | console_lock(); |
1212 | console->flags &= ~CON_ENABLED; | 1236 | console->flags &= ~CON_ENABLED; |
1213 | release_console_sem(); | 1237 | console_unlock(); |
1214 | } | 1238 | } |
1215 | EXPORT_SYMBOL(console_stop); | 1239 | EXPORT_SYMBOL(console_stop); |
1216 | 1240 | ||
1217 | void console_start(struct console *console) | 1241 | void console_start(struct console *console) |
1218 | { | 1242 | { |
1219 | acquire_console_sem(); | 1243 | console_lock(); |
1220 | console->flags |= CON_ENABLED; | 1244 | console->flags |= CON_ENABLED; |
1221 | release_console_sem(); | 1245 | console_unlock(); |
1222 | } | 1246 | } |
1223 | EXPORT_SYMBOL(console_start); | 1247 | EXPORT_SYMBOL(console_start); |
1224 | 1248 | ||
@@ -1340,7 +1364,7 @@ void register_console(struct console *newcon) | |||
1340 | * Put this console in the list - keep the | 1364 | * Put this console in the list - keep the |
1341 | * preferred driver at the head of the list. | 1365 | * preferred driver at the head of the list. |
1342 | */ | 1366 | */ |
1343 | acquire_console_sem(); | 1367 | console_lock(); |
1344 | if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { | 1368 | if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { |
1345 | newcon->next = console_drivers; | 1369 | newcon->next = console_drivers; |
1346 | console_drivers = newcon; | 1370 | console_drivers = newcon; |
@@ -1352,14 +1376,14 @@ void register_console(struct console *newcon) | |||
1352 | } | 1376 | } |
1353 | if (newcon->flags & CON_PRINTBUFFER) { | 1377 | if (newcon->flags & CON_PRINTBUFFER) { |
1354 | /* | 1378 | /* |
1355 | * release_console_sem() will print out the buffered messages | 1379 | * console_unlock(); will print out the buffered messages |
1356 | * for us. | 1380 | * for us. |
1357 | */ | 1381 | */ |
1358 | spin_lock_irqsave(&logbuf_lock, flags); | 1382 | spin_lock_irqsave(&logbuf_lock, flags); |
1359 | con_start = log_start; | 1383 | con_start = log_start; |
1360 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1384 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1361 | } | 1385 | } |
1362 | release_console_sem(); | 1386 | console_unlock(); |
1363 | console_sysfs_notify(); | 1387 | console_sysfs_notify(); |
1364 | 1388 | ||
1365 | /* | 1389 | /* |
@@ -1396,7 +1420,7 @@ int unregister_console(struct console *console) | |||
1396 | return braille_unregister_console(console); | 1420 | return braille_unregister_console(console); |
1397 | #endif | 1421 | #endif |
1398 | 1422 | ||
1399 | acquire_console_sem(); | 1423 | console_lock(); |
1400 | if (console_drivers == console) { | 1424 | if (console_drivers == console) { |
1401 | console_drivers=console->next; | 1425 | console_drivers=console->next; |
1402 | res = 0; | 1426 | res = 0; |
@@ -1418,7 +1442,7 @@ int unregister_console(struct console *console) | |||
1418 | if (console_drivers != NULL && console->flags & CON_CONSDEV) | 1442 | if (console_drivers != NULL && console->flags & CON_CONSDEV) |
1419 | console_drivers->flags |= CON_CONSDEV; | 1443 | console_drivers->flags |= CON_CONSDEV; |
1420 | 1444 | ||
1421 | release_console_sem(); | 1445 | console_unlock(); |
1422 | console_sysfs_notify(); | 1446 | console_sysfs_notify(); |
1423 | return res; | 1447 | return res; |
1424 | } | 1448 | } |