Bug 213165 - selinux_inode_free_security NULL dereference
Summary: selinux_inode_free_security NULL dereference
Alias: None
Product: Fedora
Classification: Fedora
Component: kernel
Version: 6
Hardware: All
OS: Linux
Target Milestone: ---
Assignee: Eric Paris
QA Contact: Brian Brock
Depends On:
TreeView+ depends on / blocked
Reported: 2006-10-31 01:00 UTC by Dave Jones
Modified: 2015-01-04 22:29 UTC (History)
4 users (show)

Clone Of:
Last Closed: 2007-10-22 17:31:05 UTC

Attachments (Terms of Use)

Description Dave Jones 2006-10-31 01:00:25 UTC
whilst installing an rpm, I hit this..

BUG: unable to handle kernel NULL pointer dereference at virtual address 0000000e
 printing eip:
*pde = 38fd6067
Oops: 0000 [#1]
last sysfs file: /class/net/eth0/address
Modules linked in: rfcomm hidp l2cap bluetooth ohci1394 ieee1394 button nfs
lockd fscache nfs_acl autofs4 sunrpc ip_conntrack_netbios_ns ipt_REJECT xt_state 
ip_conntrack nfnetlink iptable_filter ip_tables ip6t_REJECT xt_tcpudp
ip6table_filter ip6_tables x_tables cpufreq_ondemand dm_multipath video sbs
i2c_ec dock
 battery asus_acpi ac ipv6 parport_pc lp parport snd_hda_intel snd_hda_codec
snd_seq_dummy snd_seq_oss snd_seq_midi_event joydev snd_seq snd_seq_device snd_p
cm_oss snd_mixer_oss snd_pcm snd_timer i2c_i801 snd sg i2c_core soundcore pcspkr
serio_raw tg3 ide_cd snd_page_alloc cdrom dm_snapshot dm_zero dm_mirror dm_m
od ata_piix libata sd_mod scsi_mod ext3 jbd ehci_hcd ohci_hcd uhci_hcd
CPU:    0
EIP:    0060:[<c04c26bb>]    Not tainted VLI
EFLAGS: 00010282   (2.6.18-1.2798.fc6 #1) 
EIP is at selinux_inode_free_security+0x21/0x59
eax: f7d500f0   ebx: 0000000a   ecx: 00000003   edx: 00000000
esi: c076f86c   edi: f745a588   ebp: f7fb0f08   esp: f7fb0ed8
ds: 007b   es: 007b   ss: 0068
Process kswapd0 (pid: 231, ti=f7fb0000 task=f7d500f0 task.ti=f7fb0000)
Stack: c076f86c c076f874 0000006d c0485107 c076f86c c04856ec c587bd5c 00000000 
       00000080 00000080 c0485895 00000080 c076facc c0769b8c 00001e78 f7ffb460 
       00000080 000000d0 c045b0c3 00000000 f7fb0f88 c0458729 00079e00 00000000 
Call Trace:
 [<c0485107>] destroy_inode+0x22/0x45
 [<c04856ec>] dispose_list+0x8e/0xb7
 [<c0485895>] shrink_icache_memory+0x180/0x1a8
 [<c045b0c3>] shrink_slab+0xd9/0x142
 [<c045b471>] kswapd+0x2c9/0x3b6
 [<c04369f3>] kthread+0xc0/0xed
 [<c0404dab>] kernel_thread_helper+0x7/0x10
DWARF2 unwinder stuck at kernel_thread_helper+0x7/0x10
Leftover inexact backtrace:
Code: 5b 5e 5f 5d c3 e9 df 57 00 00 57 56 89 c6 53 8b 98 9c 01 00 00 8b 80 c0 00
00 00 8b b8 84 00 00 00 83 c7 48 89 f8 e8 60 18 15 00 <8b> 4b 04 8d 53 04 39
 d1 74 0e 8b 42 04 89 41 04 89 08 89 52 04 
EIP: [<c04c26bb>] selinux_inode_free_security+0x21/0x59 SS:ESP 0068:f7fb0ed8

Comment 1 James Morris 2006-10-31 04:10:00 UTC
What do you get with gdb on vmlinux and 'l *0xc04c26bb' ?

I'm guessing we're still trying to reference an inode in SELinux while 
it's being destroyed under memory pressure.

Comment 2 Stephen Smalley 2006-10-31 14:49:01 UTC
NULL deref was in inode_free_security called by destroy_inode to free the inode
security struct.  If the inode or its security struct was already freed, the
real bug happened earlier; this is just the messenger.  inode_free_security also
dereferences inode->i_sb->s_security, but that should be valid until
destroy_super calls selinux_sb_free_security just prior to freeing the
superblock itself.  As destroy_inode dereferences inode->i_sb itself, that
shouldn't be gone yet either.

Comment 3 Eric Paris 2006-10-31 14:51:25 UTC
> What do you get with gdb on vmlinux and 'l *0xc04c26bb' ?

0xc04c26bb is in selinux_inode_free_security (include/linux/list.h:299).
294      * list_empty - tests whether a list is empty
295      * @head: the list to test.
296      */
297     static inline int list_empty(const struct list_head *head)
298     {
299             return head->next == head;
300     }
302     /**
303      * list_empty_careful - tests whether a list is empty and not being modified

Comment 4 Eric Paris 2006-10-31 21:24:51 UTC
Wow, ok now i'm totally lost.  isec->list is actually a struct list_head embeded
in the inode_security_struct.  It is not a pointer to a struct list_head.  Thus
we see in inode_free_security

static void inode_free_security(struct inode *inode)
        if (!list_empty(&isec->list))

So we are passing &isec->list to list_empty()  Since inode_security_struct is
deined as:

struct inode_security_struct {
        struct inode *inode;           /* back pointer to inode object */
        struct list_head list;         /* list of inode_security_struct */
        u32 task_sid;        /* SID of creating task */

I was under the impression that &isec->list = isec + sizeof(struct inode *) =
isec + 4

But then when we get into list_empty it is saying that we tried to dereference
memory at 0000000e.  So I have no idea where it got 0000000e.  I just don't
understand how this can be anything other than hardware or maybe a compiler
problem (I haven't looked at the assembly around this area yet)  But it
certainly looks like the value of struct list_head *head in list_empty is messed
up but there doesn't appear to be any way in the code for that to happen....

Comment 5 Stephen Smalley 2006-11-01 18:42:45 UTC
(In reply to comment #4)
> I was under the impression that &isec->list = isec + sizeof(struct inode *) =
> isec + 4

Was the hardware x86_64?

Also, structs aren't necessarily packed.

Comment 6 Eric Paris 2006-11-01 19:16:49 UTC
Since the backtrace was all 32 bit I assumed i686 not x86_64

Comment 7 Stephen Smalley 2006-11-01 19:38:11 UTC
ebx = 0000000a
ebx+4 = 0000000e
Assuming that ebx holds isec there.

Comment 8 Stephen Smalley 2006-11-01 19:58:20 UTC
Anyway, if that is correct, isec aka inode->i_security is already corrupt on
entry to inode_free_security, and this is just the messenger, not the cause of
the bug.  
Seeing the state of the relevant inode would be interesting.

Comment 9 Eric Paris 2006-11-01 21:50:15 UTC
As usual you are correct.  

Dave, can I assume you do not have a core dump from this?  If you do can I get
it?  Any way you know to reproduce it?

From looking at the assembly, the inode is at %esi and it must be corrupted. 
ebx is actually supposed to be i_security as you thought.  edi - 0x48 is the
s_security which at least is in kernel memory.  I'll troll around tomorrow
looking for anything that plays with setting/changing i_security or the inode
fields around it, but I doubt I find anything...

Comment 10 Dave Jones 2006-11-17 03:31:44 UTC
I didn't get a coredump, and I only saw it happen once after doing an FC6
install and then a yum update to suck down a hundred or so RPMs.

No other boxes that I've done an identical procedure on have hit this.

That was on a 32bit core duo laptop btw.

Comment 11 Eric Paris 2007-10-22 17:31:05 UTC
I don't see what I can do here.  Haven't seen it since F6.  Closing as worksforme

Note You need to log in before you can comment on or make changes to this bug.