[Nouveau] 2.6.39-rc6, nouveau: unload trips on freed memory (SLUB poison)
Bruno Prémont
bonbons at linux-vserver.org
Thu May 5 13:19:22 PDT 2011
With 2.6.39-rc6 I'm hitting the following (relevant part from objdump of
drm_mm.o at bottom).
Some part of node passed to drm_mm_remove_node() is being use after free
and hits SLUB poison.
Bruno
[ 328.447498] drm: unregistered panic notifier
[ 328.447648] [drm] nouveau 0000:02:00.0: 0xAFD8: Parsing digital output script table
[ 328.448642] [drm] nouveau 0000:02:00.0: Restoring VGA fonts
[ 328.450949] [drm:drm_mm_takedown] *ERROR* Memory manager not clean. Delaying takedown
[ 328.451141] BUG: unable to handle kernel paging request at 6b6b6b6f
[ 328.451275] IP: [<c124d39a>] drm_mm_remove_node+0x5a/0xc0
[ 328.451391] *pde = 00000000
[ 328.451479] Oops: 0002 [#1]
previous Oops was complaint about CAP_SYS_ADMIN versus CAP_SYSLOG
[ 328.451566] last sysfs file: /sys/devices/platform/w83627hf.656/temp3_input
[ 328.451625] Modules linked in: nouveau(-) ttm drm_kms_helper video nfs lockd nfs_acl sunrpc snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm pcspkr snd_timer snd snd_page_alloc
[ 328.452361]
[ 328.452410] Pid: 1740, comm: rmmod Tainted: G W 2.6.39-rc6-jupiter-00001-g443badf-dirty #11 NVIDIA Corporation. nFORCE-MCP/MS-6373
[ 328.452594] EIP: 0060:[<c124d39a>] EFLAGS: 00010202 CPU: 0
[ 328.452650] EIP is at drm_mm_remove_node+0x5a/0xc0
[ 328.452703] EAX: da4dd240 EBX: dcf44be0 ECX: dcf44bd0 EDX: dcf44bd8
[ 328.452759] ESI: 6b6b6b6b EDI: 6b6b6b6b EBP: dd64fdb8 ESP: dd64fdac
[ 328.452815] DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068
[ 328.452870] Process rmmod (pid: 1740, ti=dd64e000 task=dd7fe120 task.ti=dd64e000)
[ 328.452931] Stack:
[ 328.452978] da4dd240 dcf44bd0 da4dd150 dd64fdc8 c124d417 dbebfb04 00000000 dd64fdd4
[ 328.453360] deb9f281 00000090 dd64fde0 deb99853 dbebfad0 dd64fdf0 deb99b5e dbf00148
[ 328.453717] dbebfad0 dd64fe18 deb9beed 00000000 00000000 def5e632 00004d98 00000000
[ 328.454099] Call Trace:
[ 328.454153] [<c124d417>] drm_mm_put_block+0x17/0x50
[ 328.454223] [<deb9f281>] ttm_bo_man_put_node+0x11/0x20 [ttm]
[ 328.454283] [<deb99853>] ttm_bo_mem_put+0x23/0x30 [ttm]
[ 328.454364] [<deb99b5e>] ttm_bo_cleanup_memtype_use+0x2e/0x60 [ttm]
[ 328.454425] [<deb9beed>] ttm_bo_release+0x17d/0x1b0 [ttm]
[ 328.454516] [<def5e632>] ? nouveau_gpuobj_takedown+0x92/0x100 [nouveau]
[ 328.454578] [<deb9bd70>] ? ttm_bo_create+0xf0/0xf0 [ttm]
[ 328.454639] [<c11bd8ec>] kref_put+0x2c/0x60
[ 328.454697] [<deb99aa8>] ttm_bo_unref+0x18/0x20 [ttm]
[ 328.454762] [<def5dd77>] nouveau_mem_vram_fini+0x37/0xa0 [nouveau]
[ 328.454829] [<def59c85>] nouveau_unload+0xd5/0x150 [nouveau]
[ 328.454888] [<c1248e03>] drm_put_dev+0xb3/0x1c0
[ 328.454953] [<def59010>] nouveau_pci_remove+0x10/0x20 [nouveau]
[ 328.455010] [<c11d0baf>] pci_device_remove+0x3f/0xf0
[ 328.455070] [<c12611cb>] __device_release_driver+0x4b/0xa0
[ 328.455126] [<c1261297>] driver_detach+0x77/0x80
[ 328.455181] [<c126057b>] bus_remove_driver+0x5b/0xa0
[ 328.455236] [<c1261ae6>] driver_unregister+0x46/0x80
[ 328.455314] [<c110087f>] ? sysfs_remove_file+0xf/0x20
[ 328.455369] [<c11d0e4a>] pci_unregister_driver+0x2a/0x70
[ 328.455438] [<c124acaf>] drm_pci_exit+0x7f/0x90
[ 328.455506] [<defd5f17>] nouveau_exit+0x1b/0x22 [nouveau]
[ 328.455564] [<c105cdbb>] sys_delete_module+0x19b/0x1f0
[ 328.455622] [<c10a42d2>] ? do_munmap+0x212/0x2f0
[ 328.455678] [<c13971d7>] sysenter_do_call+0x12/0x26
[ 328.455731] Code: 8b 70 08 8b 58 0c 89 5e 04 89 33 c7 40 08 00 01 10 00 c7 40 0c 00 02 20 00 0f b6 5a 10 f6 c3 01 74 57 8b 7a 08 8b 72 0c 8d 5a 08
[ 328.457446] 77 04 89 3e 8b 31 89 5e 04 89 72 08 89 4a 0c 89 19 8b 08 8b
[ 328.458342] EIP: [<c124d39a>] drm_mm_remove_node+0x5a/0xc0 SS:ESP 0068:dd64fdac
[ 328.458481] CR2: 000000006b6b6b6f
[ 328.459085] ---[ end trace cb7019e5756bd7f0 ]---
[ 502.313511] =============================================================================
[ 502.313597] BUG kmalloc-96: Poison overwritten
[ 502.313650] -----------------------------------------------------------------------------
[ 502.313653]
[ 502.313774] INFO: 0xdcf44bd0-0xdcf44bd7. First byte 0xd0 instead of 0x6b
[ 502.313832] INFO: Slab 0xddfce880 objects=36 used=26 fp=0xdcf44bd0 flags=0x400000c0
[ 502.313895] INFO: Object 0xdcf44bd0 @offset=3024 fp=0xdcf44e00
[ 502.313897]
[ 502.313995] Bytes b4 0xdcf44bc0: cc cc cc cc d0 4b f4 dc 5a 5a 5a 5a 5a 5a 5a 5a <CC><CC><CC><CC><D0>K<F4><DC>ZZZZZZZZ
[ 502.314708] Object 0xdcf44bd0: d0 4b f4 dc d0 4b f4 dc 6b 6b 6b 6b 6b 6b 6b 6b <D0>K<F4><DC><D0>K<F4><DC>kkkkkkkk
[ 502.315417] Object 0xdcf44be0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
[ 502.316134] Object 0xdcf44bf0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
[ 502.316852] Object 0xdcf44c00: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
[ 502.317570] Object 0xdcf44c10: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
[ 502.318286] Object 0xdcf44c20: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk<A5>
[ 502.319014] Redzone 0xdcf44c30: bb bb bb bb <BB><BB><BB><BB>
[ 502.319724] Padding 0xdcf44c38: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
[ 502.320004] Pid: 1750, comm: agetty Tainted: G D W 2.6.39-rc6-jupiter-00001-g443badf-dirty #11
[ 502.320004] Call Trace:
[ 502.320004] [<c10afe33>] print_trailer+0xe3/0x130
[ 502.320004] [<c10b0244>] check_bytes_and_report+0xc4/0x100
[ 502.320004] [<c10b1277>] check_object+0x1c7/0x210
[ 502.320004] [<c10b1752>] alloc_debug_processing+0xc2/0x140
[ 502.320004] [<c10b1942>] T.1001+0x172/0x1a0
[ 502.320004] [<c10f8b31>] ? __proc_create+0x81/0x110
[ 502.320004] [<c10f8b31>] ? __proc_create+0x81/0x110
[ 502.320004] [<c10b1d60>] __kmalloc+0x180/0x1a0
[ 502.320004] [<c10f8b31>] ? __proc_create+0x81/0x110
[ 502.320004] [<c10f8b31>] __proc_create+0x81/0x110
[ 502.320004] [<c10f92f3>] proc_mkdir_mode+0x23/0x50
[ 502.320004] [<c10f932f>] proc_mkdir+0xf/0x20
[ 502.320004] [<c106a229>] register_handler_proc+0xd9/0xf0
[ 502.320004] [<c1068063>] __setup_irq+0x1e3/0x330
[ 502.320004] [<c10b1b0c>] ? kmem_cache_alloc_trace+0x9c/0xf0
[ 502.320004] [<c10688eb>] ? request_threaded_irq+0x7b/0x120
[ 502.320004] [<c1237b60>] ? serial8250_handle_port+0x2c0/0x2c0
[ 502.320004] [<c106892e>] request_threaded_irq+0xbe/0x120
[ 502.320004] [<c1236681>] serial8250_startup+0x5c1/0x600
[ 502.320004] [<c1233114>] uart_startup+0x44/0x130
[ 502.320004] [<c12332f5>] uart_open+0xf5/0x180
[ 502.320004] [<c121ea9a>] tty_open+0x1fa/0x490
[ 502.320004] [<c10bbff6>] chrdev_open+0xa6/0x190
[ 502.320004] [<c10b7733>] __dentry_open+0x103/0x2a0
[ 502.320004] [<c10b79b6>] nameidata_to_filp+0x66/0x80
[ 502.320004] [<c10bbf50>] ? register_chrdev_region+0xa0/0xa0
[ 502.320004] [<c10c3150>] do_last+0x1a0/0x700
[ 502.320004] [<c10c42c2>] path_openat+0x92/0x320
[ 502.320004] [<c10b02b8>] ? init_object+0x38/0x70
[ 502.320004] [<c10c4630>] do_filp_open+0x30/0x80
[ 502.320004] [<c10ce572>] ? alloc_fd+0x62/0xe0
[ 502.320004] [<c10c2741>] ? getname_flags+0x61/0xe0
[ 502.320004] [<c10b87ed>] do_sys_open+0xed/0x1e0
[ 502.320004] [<c10b8949>] sys_open+0x29/0x40
[ 502.320004] [<c13971d7>] sysenter_do_call+0x12/0x26
[ 502.320004] FIX kmalloc-96: Restoring 0xdcf44bd0-0xdcf44bd7=0x6b
[ 502.320004]
[ 502.320004] FIX kmalloc-96: Marking all objects used
00000720 <drm_mm_remove_node>:
/**
* Remove a memory node from the allocator.
*/
void drm_mm_remove_node(struct drm_mm_node *node)
{
720: 55 push %ebp
struct drm_mm *mm = node->mm;
721: 8b 48 1c mov 0x1c(%eax),%ecx
/**
* Remove a memory node from the allocator.
*/
void drm_mm_remove_node(struct drm_mm_node *node)
{
724: 89 e5 mov %esp,%ebp
726: 57 push %edi
727: 56 push %esi
728: 53 push %ebx
struct drm_mm *mm = node->mm;
struct drm_mm_node *prev_node;
BUG_ON(node->scanned_block || node->scanned_prev_free
729: 0f b6 58 10 movzbl 0x10(%eax),%ebx
72d: f6 c3 0e test $0xe,%bl
730: 0f 85 9d 00 00 00 jne 7d3 <drm_mm_remove_node+0xb3>
|| node->scanned_next_free);
prev_node =
list_entry(node->node_list.prev, struct drm_mm_node, node_list);
if (node->hole_follows) {
736: 83 e3 01 and $0x1,%ebx
BUG_ON(node->scanned_block || node->scanned_prev_free
|| node->scanned_next_free);
prev_node =
list_entry(node->node_list.prev, struct drm_mm_node, node_list);
739: 8b 50 04 mov 0x4(%eax),%edx
if (node->hole_follows) {
73c: 74 72 je 7b0 <drm_mm_remove_node+0x90>
}
static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
struct drm_mm_node *next_node =
list_entry(hole_node->node_list.next, struct drm_mm_node,
73e: 8b 30 mov (%eax),%esi
prev_node =
list_entry(node->node_list.prev, struct drm_mm_node, node_list);
if (node->hole_follows) {
BUG_ON(drm_mm_hole_node_start(node)
740: 8b 58 18 mov 0x18(%eax),%ebx
743: 03 58 14 add 0x14(%eax),%ebx
}
static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
struct drm_mm_node *next_node =
list_entry(hole_node->node_list.next, struct drm_mm_node,
746: 3b 5e 14 cmp 0x14(%esi),%ebx
749: 0f 84 88 00 00 00 je 7d7 <drm_mm_remove_node+0xb7>
__list_del(entry->prev, entry->next);
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
74f: 8b 70 08 mov 0x8(%eax),%esi
752: 8b 58 0c mov 0xc(%eax),%ebx
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
755: 89 5e 04 mov %ebx,0x4(%esi)
prev->next = next;
758: 89 33 mov %esi,(%ebx)
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
75a: c7 40 08 00 01 10 00 movl $0x100100,0x8(%eax)
entry->prev = LIST_POISON2;
761: c7 40 0c 00 02 20 00 movl $0x200200,0xc(%eax)
list_del(&node->hole_stack);
} else
BUG_ON(drm_mm_hole_node_start(node)
!= drm_mm_hole_node_end(node));
if (!prev_node->hole_follows) {
768: 0f b6 5a 10 movzbl 0x10(%edx),%ebx
76c: f6 c3 01 test $0x1,%bl
76f: 74 57 je 7c8 <drm_mm_remove_node+0xa8>
* in an undefined state.
*/
#ifndef CONFIG_DEBUG_LIST
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
771: 8b 7a 08 mov 0x8(%edx),%edi
774: 8b 72 0c mov 0xc(%edx),%esi
prev_node->hole_follows = 1;
list_add(&prev_node->hole_stack, &mm->hole_stack);
} else
list_move(&prev_node->hole_stack, &mm->hole_stack);
777: 8d 5a 08 lea 0x8(%edx),%ebx
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
77a: 89 77 04 mov %esi,0x4(%edi)
prev->next = next;
77d: 89 3e mov %edi,(%esi)
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
77f: 8b 31 mov (%ecx),%esi
#ifndef CONFIG_DEBUG_LIST
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
781: 89 5e 04 mov %ebx,0x4(%esi)
new->next = next;
784: 89 72 08 mov %esi,0x8(%edx)
new->prev = prev;
787: 89 4a 0c mov %ecx,0xc(%edx)
prev->next = new;
78a: 89 19 mov %ebx,(%ecx)
__list_del(entry->prev, entry->next);
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
78c: 8b 08 mov (%eax),%ecx
78e: 8b 50 04 mov 0x4(%eax),%edx
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
791: 89 51 04 mov %edx,0x4(%ecx)
prev->next = next;
794: 89 0a mov %ecx,(%edx)
list_del(&node->node_list);
node->allocated = 0;
}
796: 5b pop %ebx
797: 5e pop %esi
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
798: c7 00 00 01 10 00 movl $0x100100,(%eax)
entry->prev = LIST_POISON2;
79e: c7 40 04 00 02 20 00 movl $0x200200,0x4(%eax)
list_add(&prev_node->hole_stack, &mm->hole_stack);
} else
list_move(&prev_node->hole_stack, &mm->hole_stack);
list_del(&node->node_list);
node->allocated = 0;
7a5: 80 60 10 df andb $0xdf,0x10(%eax)
}
7a9: 5f pop %edi
7aa: c9 leave
7ab: c3 ret
7ac: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
}
static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
struct drm_mm_node *next_node =
list_entry(hole_node->node_list.next, struct drm_mm_node,
7b0: 8b 30 mov (%eax),%esi
if (node->hole_follows) {
BUG_ON(drm_mm_hole_node_start(node)
== drm_mm_hole_node_end(node));
list_del(&node->hole_stack);
} else
BUG_ON(drm_mm_hole_node_start(node)
7b2: 8b 58 18 mov 0x18(%eax),%ebx
7b5: 03 58 14 add 0x14(%eax),%ebx
}
static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
struct drm_mm_node *next_node =
list_entry(hole_node->node_list.next, struct drm_mm_node,
7b8: 3b 5e 14 cmp 0x14(%esi),%ebx
7bb: 74 ab je 768 <drm_mm_remove_node+0x48>
if (node->hole_follows) {
BUG_ON(drm_mm_hole_node_start(node)
== drm_mm_hole_node_end(node));
list_del(&node->hole_stack);
} else
BUG_ON(drm_mm_hole_node_start(node)
7bd: 0f 0b ud2a
7bf: eb fe jmp 7bf <drm_mm_remove_node+0x9f>
7c1: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
!= drm_mm_hole_node_end(node));
if (!prev_node->hole_follows) {
prev_node->hole_follows = 1;
7c8: 83 cb 01 or $0x1,%ebx
7cb: 88 5a 10 mov %bl,0x10(%edx)
list_add(&prev_node->hole_stack, &mm->hole_stack);
7ce: 8d 5a 08 lea 0x8(%edx),%ebx
7d1: eb ac jmp 77f <drm_mm_remove_node+0x5f>
void drm_mm_remove_node(struct drm_mm_node *node)
{
struct drm_mm *mm = node->mm;
struct drm_mm_node *prev_node;
BUG_ON(node->scanned_block || node->scanned_prev_free
7d3: 0f 0b ud2a
7d5: eb fe jmp 7d5 <drm_mm_remove_node+0xb5>
prev_node =
list_entry(node->node_list.prev, struct drm_mm_node, node_list);
if (node->hole_follows) {
BUG_ON(drm_mm_hole_node_start(node)
7d7: 0f 0b ud2a
7d9: eb fe jmp 7d9 <drm_mm_remove_node+0xb9>
7db: 90 nop
7dc: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
More information about the Nouveau
mailing list