mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
s390/debug: Fix race between debug area resize and event logging
Trace functions check for non-NULL id->areas without lock to minimize overhead. This opens a race window where a NULL pointer dereference occurs if id->areas is set to NULL (e.g. via echo 0 > ../pages) after the check and before id->lock is taken. Fix this by rechecking id->areas under lock. Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
parent
22d4210bf9
commit
0945285e6c
|
|
@ -1283,7 +1283,7 @@ void debug_set_critical(void)
|
|||
debug_entry_t *debug_event_common(debug_info_t *id, int level, const void *buf,
|
||||
int len)
|
||||
{
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (!debug_active || !id->areas)
|
||||
|
|
@ -1294,6 +1294,8 @@ debug_entry_t *debug_event_common(debug_info_t *id, int level, const void *buf,
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
do {
|
||||
active = get_active_entry(id);
|
||||
memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
|
||||
|
|
@ -1303,7 +1305,7 @@ debug_entry_t *debug_event_common(debug_info_t *id, int level, const void *buf,
|
|||
len -= id->buf_size;
|
||||
buf += id->buf_size;
|
||||
} while (len > 0);
|
||||
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
return active;
|
||||
}
|
||||
|
|
@ -1316,7 +1318,7 @@ EXPORT_SYMBOL(debug_event_common);
|
|||
debug_entry_t *debug_exception_common(debug_info_t *id, int level,
|
||||
const void *buf, int len)
|
||||
{
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (!debug_active || !id->areas)
|
||||
|
|
@ -1327,6 +1329,8 @@ debug_entry_t *debug_exception_common(debug_info_t *id, int level,
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
do {
|
||||
active = get_active_entry(id);
|
||||
memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
|
||||
|
|
@ -1336,7 +1340,7 @@ debug_entry_t *debug_exception_common(debug_info_t *id, int level,
|
|||
len -= id->buf_size;
|
||||
buf += id->buf_size;
|
||||
} while (len > 0);
|
||||
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
return active;
|
||||
}
|
||||
|
|
@ -1362,7 +1366,7 @@ static inline int debug_count_numargs(char *string)
|
|||
debug_entry_t *__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
|
||||
{
|
||||
debug_sprintf_entry_t *curr_event;
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
int numargs, idx;
|
||||
va_list ap;
|
||||
|
|
@ -1377,6 +1381,8 @@ debug_entry_t *__debug_sprintf_event(debug_info_t *id, int level, char *string,
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
active = get_active_entry(id);
|
||||
curr_event = (debug_sprintf_entry_t *) DEBUG_DATA(active);
|
||||
va_start(ap, string);
|
||||
|
|
@ -1385,6 +1391,7 @@ debug_entry_t *__debug_sprintf_event(debug_info_t *id, int level, char *string,
|
|||
curr_event->args[idx] = va_arg(ap, long);
|
||||
va_end(ap);
|
||||
debug_finish_entry(id, active, level, 0);
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
return active;
|
||||
|
|
@ -1397,7 +1404,7 @@ EXPORT_SYMBOL(__debug_sprintf_event);
|
|||
debug_entry_t *__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
|
||||
{
|
||||
debug_sprintf_entry_t *curr_event;
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
int numargs, idx;
|
||||
va_list ap;
|
||||
|
|
@ -1413,6 +1420,8 @@ debug_entry_t *__debug_sprintf_exception(debug_info_t *id, int level, char *stri
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
active = get_active_entry(id);
|
||||
curr_event = (debug_sprintf_entry_t *)DEBUG_DATA(active);
|
||||
va_start(ap, string);
|
||||
|
|
@ -1421,6 +1430,7 @@ debug_entry_t *__debug_sprintf_exception(debug_info_t *id, int level, char *stri
|
|||
curr_event->args[idx] = va_arg(ap, long);
|
||||
va_end(ap);
|
||||
debug_finish_entry(id, active, level, 1);
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
return active;
|
||||
|
|
@ -1663,9 +1673,11 @@ static void debug_flush(debug_info_t *id, int area)
|
|||
unsigned long flags;
|
||||
int i, j;
|
||||
|
||||
if (!id || !id->areas)
|
||||
if (!id)
|
||||
return;
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
if (area == DEBUG_FLUSH_ALL) {
|
||||
id->active_area = 0;
|
||||
memset(id->active_entries, 0, id->nr_areas * sizeof(int));
|
||||
|
|
@ -1680,6 +1692,7 @@ static void debug_flush(debug_info_t *id, int area)
|
|||
for (i = 0; i < id->pages_per_area; i++)
|
||||
memset(id->areas[area][i], 0, PAGE_SIZE);
|
||||
}
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user