general protection fault in security_d_instantiate

Status: upstream: reported C repro on 2026/11/14 14:11
Subsystems: lsm
Labels: prio:normal
[Documentation on labels]
Reported-by: syzbot+d8a69701a6e796ad5d3e@syzkaller.appspotmail.com
First crash: 15h00m, last: 30m
✨ AI-generated root cause summary:

In squashfs_read_inode(), validation checks for directory types SQUASHFS_DIR_TYPE and SQUASHFS_LDIR_TYPE jump to failed_read when inode->i_size < 3 without initializing err to a negative errno (-EINVAL). Consequently, err retains the positive byte count returned by the preceding squashfs_read_metadata() call (sizeof(struct squashfs_dir_inode) == 32 == 0x20, or 40 == 0x28 for LDIR). When squashfs_iget() receives this positive return value, it invokes ERR_PTR(err), yielding an invalid non-negative pointer (e.g. (void *)0x20) that bypasses IS_ERR() and NULL checks in d_splice_alias_ops(). Passing this bogus inode pointer to security_d_instantiate() causes a NULL-pointer dereference when reading inode->i_flags at offset 0x24.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 84abb955b101:

Root Cause Analysis

Involved Components

  • Source Files: fs/squashfs/inode.c, fs/squashfs/namei.c, fs/dcache.c, security/security.c
  • Functions: squashfs_read_inode(), squashfs_iget(), squashfs_lookup(), d_splice_alias(), d_splice_alias_ops(), security_d_instantiate()
  • Structures and Fields: struct squashfs_dir_inode, struct squashfs_ldir_inode, struct inode::i_size, struct inode::i_flags

Mechanism and Failure Chain

  1. Missing Error Code Assignment in squashfs_read_inode(): In fs/squashfs/inode.c, squashfs_read_inode() reads inode metadata from disk using squashfs_read_metadata():

    case SQUASHFS_DIR_TYPE: {
        struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;
    
        err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
                sizeof(*sqsh_ino));
        if (err < 0)
            goto failed_read;
    
        /* The directory size must be 3 or larger, as it includes "." and ".." entries */
        inode->i_size = le16_to_cpu(sqsh_ino->file_size);
        if (inode->i_size < 3)
            goto failed_read;
    

    squashfs_read_metadata() returns the number of bytes read on success. For SQUASHFS_DIR_TYPE, sizeof(struct squashfs_dir_inode) is 32 (0x20) (and 40 / 0x28 for SQUASHFS_LDIR_TYPE). When inode->i_size < 3, execution jumps to failed_read without assigning err = -EINVAL; (unlike the other failure paths in squashfs_read_inode(), such as corrupted regular files or symlinks). Consequently, failed_read: returns the positive value err = 32 (0x20).

  2. Violation of ERR_PTR Invariant in squashfs_iget(): In squashfs_iget() (fs/squashfs/inode.c:93-97):

    err = squashfs_read_inode(inode, ino);
    if (err) {
        iget_failed(inode);
        return ERR_PTR(err);
    }
    

    The kernel convention and contract for ERR_PTR() requires a negative error code (e.g., -EINVAL / -22). Passing a positive integer 32 produces (struct inode *)(long)32, i.e., (struct inode *)0x0000000000000020.

  3. Bypassing Error and NULL Validation in d_splice_alias_ops(): In squashfs_lookup() (fs/squashfs/namei.c:265):

    inode = squashfs_iget(dir->i_sb, ino, ino_num);
    goto exit_lookup;
    ...
    exit_lookup:
        kfree(dire);
        return d_splice_alias(inode, dentry);
    

    squashfs_lookup() passes inode = (void *)0x20 to d_splice_alias(), which calls d_splice_alias_ops() (fs/dcache.c:3447):

    struct dentry *d_splice_alias_ops(struct inode *inode, struct dentry *dentry,
                      const struct dentry_operations *ops)
    {
        if (IS_ERR(inode))
            return ERR_CAST(inode);
    
        BUG_ON(d_really_is_positive(dentry));
    
        if (!inode)
            goto out;
    
        security_d_instantiate(dentry, inode);
    

    IS_ERR() tests whether the pointer value falls within the range [(unsigned long)-MAX_ERRNO, (unsigned long)-1]. Since 0x20 is neither within that range nor NULL, both checks evaluate to false. d_splice_alias_ops() treats 0x20 as a legitimate inode pointer.

  4. Kernel Oops in security_d_instantiate(): security_d_instantiate() (security/security.c:3781) executes:

    void security_d_instantiate(struct dentry *dentry, struct inode *inode)
    {
        if (unlikely(inode && IS_PRIVATE(inode)))
            return;
    

    IS_PRIVATE(inode) evaluates (inode)->i_flags & S_PRIVATE. In struct inode, i_flags is located at byte offset 4 (bits 32..63). Accessing inode->i_flags attempts to read address 0x20 + 0x4 = 0x24. Under KASAN, shadow address calculation accesses (0x24 >> 3) + 0xdffffc0000000000 = 0xdffffc0000000004, generating a General Protection Fault and a null-ptr-deref in range [0x0000000000000020-0x0000000000000027]. In production kernels without KASAN, dereferencing 0x24 within unmapped page 0 generates a NULL-pointer dereference page fault oops/panic.

▶ ▼ ✨ AI Jobs (1)
ID Workflow Result Correct Bug Created Started Finished Revision
2fadee5f assessment-security DenialOfService: ✅ Exploitable: ❌ FilesystemTrigger: ✅ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ general protection fault in security_d_instantiate 2026/11/13 23:41 2026/11/13 23:41 2026/11/14 00:14 819ebe34
▶ ▼ Discussions (1)
Title Replies (including bot) Last reply
[syzbot] [lsm?] general protection fault in security_d_instantiate 0 (1) 2026/11/14 14:11

Sample crash report:
loop0: detected capacity change from 0 to 8
SQUASHFS error: Unable to read inode 0x87
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000004: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x0000000000000020-0x0000000000000027]
CPU: 1 UID: 0 PID: 5647 Comm: syz-executor337 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 11/06/2026
RIP: 0010:security_d_instantiate+0x2f/0x1d0 security/security.c:3781
Code: 41 57 41 56 53 48 89 f3 49 89 fe e8 bb 2c 20 fd 48 85 db 74 42 4c 8d 7b 04 4c 89 f8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <0f> b6 04 08 84 c0 0f 85 9d 00 00 00 41 8b 2f 89 ee 81 e6 00 02 00
RSP: 0018:ffffc90003b1f758 EFLAGS: 00010203
RAX: 0000000000000004 RBX: 0000000000000020 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000020 RDI: ffff888077497d40
RBP: ffffc90003b1f9b0 R08: ffffffff91bec8bf R09: 1ffffffff237d917
R10: dffffc0000000000 R11: fffffbfff237d918 R12: 0000000000000000
R13: dffffc0000000000 R14: ffff888077497d40 R15: 0000000000000024
FS:  0000555576a8a400(0000) GS:ffff8881234cd000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00002000000000c0 CR3: 0000000034bb2000 CR4: 00000000003526f0
Call Trace:
 <TASK>
 d_splice_alias_ops+0x72/0x440 fs/dcache.c:3458
 squashfs_lookup+0xc5e/0x14e0 fs/squashfs/namei.c:273
 finish_lookup fs/namei.c:1934 [inline]
 lookup_open+0x816/0x16e0 fs/namei.c:4644
 open_last_lookups fs/namei.c:4880 [inline]
 path_openat+0x7a5/0x20e0 fs/namei.c:5119
 do_file_open+0x23e/0x4a0 fs/namei.c:5151
 do_sys_openat2+0x115/0x200 fs/open.c:1492
 do_sys_open fs/open.c:1498 [inline]
 __do_sys_openat fs/open.c:1838 [inline]
 __se_sys_openat fs/open.c:1833 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1833
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x171/0x540 arch/x86/entry/syscall_64.c:89
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x00007f101b51a909
Code: c0 79 93 eb d5 48 8d 7c 1d 00 eb 99 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 d8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffd8afc50d8 EFLAGS: 00000246 ORIG_RAX: 0000000000000101
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f101b51a909
RDX: 0000000000040042 RSI: 00002000000000c0 RDI: 00000000ffffff9c
RBP: 0000000000000001 R08: 00000000ec776000 R09: 00000000ec776000
R10: 0000000000000001 R11: 0000000000000246 R12: 00007ffd8afc5110
R13: 0000000000000002 R14: 431bde82d7b634db R15: 00007f101b57a04b
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:security_d_instantiate+0x2f/0x1d0 security/security.c:3781
Code: 41 57 41 56 53 48 89 f3 49 89 fe e8 bb 2c 20 fd 48 85 db 74 42 4c 8d 7b 04 4c 89 f8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <0f> b6 04 08 84 c0 0f 85 9d 00 00 00 41 8b 2f 89 ee 81 e6 00 02 00
RSP: 0018:ffffc90003b1f758 EFLAGS: 00010203
RAX: 0000000000000004 RBX: 0000000000000020 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000020 RDI: ffff888077497d40
RBP: ffffc90003b1f9b0 R08: ffffffff91bec8bf R09: 1ffffffff237d917
R10: dffffc0000000000 R11: fffffbfff237d918 R12: 0000000000000000
R13: dffffc0000000000 R14: ffff888077497d40 R15: 0000000000000024
FS:  0000555576a8a400(0000) GS:ffff8881234cd000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00002000000000c0 CR3: 0000000034bb2000 CR4: 00000000003526f0
----------------
Code disassembly (best guess):
   0:	41 57                	push   %r15
   2:	41 56                	push   %r14
   4:	53                   	push   %rbx
   5:	48 89 f3             	mov    %rsi,%rbx
   8:	49 89 fe             	mov    %rdi,%r14
   b:	e8 bb 2c 20 fd       	call   0xfd202ccb
  10:	48 85 db             	test   %rbx,%rbx
  13:	74 42                	je     0x57
  15:	4c 8d 7b 04          	lea    0x4(%rbx),%r15
  19:	4c 89 f8             	mov    %r15,%rax
  1c:	48 c1 e8 03          	shr    $0x3,%rax
  20:	48 b9 00 00 00 00 00 	movabs $0xdffffc0000000000,%rcx
  27:	fc ff df
* 2a:	0f b6 04 08          	movzbl (%rax,%rcx,1),%eax <-- trapping instruction
  2e:	84 c0                	test   %al,%al
  30:	0f 85 9d 00 00 00    	jne    0xd3
  36:	41 8b 2f             	mov    (%r15),%ebp
  39:	89 ee                	mov    %ebp,%esi
  3b:	81                   	.byte 0x81
  3c:	e6 00                	out    %al,$0x0
  3e:	02 00                	add    (%rax),%al

Crashes (13):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/11/14 14:10 linux-next 84abb955b101 819ebe34 .config strace log report syz / log C [disk image] [vmlinux] [kernel image] [mounted in repro] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 13:15 linux-next 84abb955b101 819ebe34 .config console log report syz / log [disk image] [vmlinux] [kernel image] [mounted in repro] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 03:05 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 03:00 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 02:58 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 02:49 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 02:49 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 02:37 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/14 02:33 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/13 23:54 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/13 23:53 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/13 23:40 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
2026/11/13 23:40 linux-next 84abb955b101 be5d1971 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-linux-next-kasan-gce-root general protection fault in security_d_instantiate
* Struck through repros no longer work on HEAD.