All of lore.kernel.org
 help / color / mirror / Atom feed
* [syzbot] [i2c?] WARNING: refcount bug in i2c_get_adapter (2)
@ 2026-04-22 20:31 syzbot
  2026-04-25 21:45 ` Arjan van de Ven
  0 siblings, 1 reply; 2+ messages in thread
From: syzbot @ 2026-04-22 20:31 UTC (permalink / raw)
  To: linux-i2c, linux-kernel, syzkaller-bugs, wsa+renesas

Hello,

syzbot found the following issue on:

HEAD commit:    e753c16cb3dd Merge tag 'spi-fix-v7.0-rc7' of git://git.ker..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=127f9106580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=45cb3c58fd963c27
dashboard link: https://syzkaller.appspot.com/bug?extid=c0291c8c9aaa473c7721
compiler:       Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/5ae80002fa8a/disk-e753c16c.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/6ef912fb95e2/vmlinux-e753c16c.xz
kernel image: https://storage.googleapis.com/syzbot-assets/b5b121be2ebf/bzImage-e753c16c.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+c0291c8c9aaa473c7721@syzkaller.appspotmail.com

------------[ cut here ]------------
refcount_t: addition on 0; use-after-free.
WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x9f/0x110 lib/refcount.c:25, CPU#0: syz.1.506/7352
Modules linked in:
CPU: 0 UID: 0 PID: 7352 Comm: syz.1.506 Tainted: G             L      syzkaller #0 PREEMPT_{RT,(full)} 
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 03/18/2026
RIP: 0010:refcount_warn_saturate+0x9f/0x110 lib/refcount.c:25
Code: eb 66 85 db 74 3e 83 fb 01 75 4c e8 bb d6 25 fd 48 8d 3d 84 01 d6 0a 67 48 0f b9 3a eb 4a e8 a8 d6 25 fd 48 8d 3d 81 01 d6 0a <67> 48 0f b9 3a eb 37 e8 95 d6 25 fd 48 8d 3d 7e 01 d6 0a 67 48 0f
RSP: 0018:ffffc9001ca9f6d8 EFLAGS: 00010283
RAX: ffffffff849eaa68 RBX: 0000000000000002 RCX: 0000000000080000
RDX: ffffc90006421000 RSI: 00000000000006c7 RDI: ffffffff8f74abf0
RBP: 0000000000000000 R08: ffff888020331e80 R09: 0000000000000005
R10: 0000000000000100 R11: 0000000000000004 R12: ffffffff8c04a688
R13: dffffc0000000000 R14: ffff88803b531188 R15: dffffc0000000000
FS:  00007f9769ca66c0(0000) GS:ffff888126332000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f6df4ab1d80 CR3: 00000000348d0000 CR4: 00000000003526f0
Call Trace:
 <TASK>
 __refcount_add include/linux/refcount.h:-1 [inline]
 __refcount_inc include/linux/refcount.h:366 [inline]
 refcount_inc include/linux/refcount.h:383 [inline]
 kref_get include/linux/kref.h:45 [inline]
 kobject_get+0xfa/0x120 lib/kobject.c:643
 i2c_get_adapter+0x6d/0xa0 drivers/i2c/i2c-core-base.c:2612
 i2cdev_open+0x48/0x190 drivers/i2c/i2c-dev.c:603
 chrdev_open+0x4d0/0x5f0 fs/char_dev.c:411
 do_dentry_open+0x83d/0x13e0 fs/open.c:949
 vfs_open+0x3b/0x350 fs/open.c:1081
 do_open fs/namei.c:4677 [inline]
 path_openat+0x2e43/0x38a0 fs/namei.c:4836
 do_file_open+0x23e/0x4a0 fs/namei.c:4865
 do_sys_openat2+0x113/0x200 fs/open.c:1366
 do_sys_open fs/open.c:1372 [inline]
 __do_sys_openat fs/open.c:1388 [inline]
 __se_sys_openat fs/open.c:1383 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1383
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f976ba0d04e
Code: 08 0f 85 a5 a8 ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 80 00 00 00 00 48 83 ec 08
RSP: 002b:00007f9769ca5b28 EFLAGS: 00000246 ORIG_RAX: 0000000000000101
RAX: ffffffffffffffda RBX: 00007f9769ca66c0 RCX: 00007f976ba0d04e
RDX: 0000000000000402 RSI: 00007f9769ca5c00 RDI: ffffffffffffff9c
RBP: 00007f9769ca5c00 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: cccccccccccccccd
R13: 00007f976bcc6038 R14: 00007f976bcc5fa0 R15: 00007fffc400e638
 </TASK>
----------------
Code disassembly (best guess):
   0:	eb 66                	jmp    0x68
   2:	85 db                	test   %ebx,%ebx
   4:	74 3e                	je     0x44
   6:	83 fb 01             	cmp    $0x1,%ebx
   9:	75 4c                	jne    0x57
   b:	e8 bb d6 25 fd       	call   0xfd25d6cb
  10:	48 8d 3d 84 01 d6 0a 	lea    0xad60184(%rip),%rdi        # 0xad6019b
  17:	67 48 0f b9 3a       	ud1    (%edx),%rdi
  1c:	eb 4a                	jmp    0x68
  1e:	e8 a8 d6 25 fd       	call   0xfd25d6cb
  23:	48 8d 3d 81 01 d6 0a 	lea    0xad60181(%rip),%rdi        # 0xad601ab
* 2a:	67 48 0f b9 3a       	ud1    (%edx),%rdi <-- trapping instruction
  2f:	eb 37                	jmp    0x68
  31:	e8 95 d6 25 fd       	call   0xfd25d6cb
  36:	48 8d 3d 7e 01 d6 0a 	lea    0xad6017e(%rip),%rdi        # 0xad601bb
  3d:	67                   	addr32
  3e:	48                   	rex.W
  3f:	0f                   	.byte 0xf


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [syzbot] [i2c?] WARNING: refcount bug in i2c_get_adapter (2)
  2026-04-22 20:31 [syzbot] [i2c?] WARNING: refcount bug in i2c_get_adapter (2) syzbot
@ 2026-04-25 21:45 ` Arjan van de Ven
  0 siblings, 0 replies; 2+ messages in thread
From: Arjan van de Ven @ 2026-04-25 21:45 UTC (permalink / raw)
  To: linux-i2c
  Cc: linux-kernel, syzkaller-bugs, wsa+renesas,
	syzbot+c0291c8c9aaa473c7721

This email is created by automation to help kernel developers
deal with a large volume of AI generated bug reports by decoding
oopses into more actionable information.


Decoded Backtrace

0. refcount_warn_saturate -- lib/refcount.c:25 (crash site)

    11  #define REFCOUNT_WARN(str) WARN_ONCE(1, "refcount_t: " str ".\n")
    12
    13  void refcount_warn_saturate(refcount_t *r,
    13                               enum refcount_saturation_type t)
    14  {
    15      refcount_set(r, REFCOUNT_SATURATED);
    16
    17      switch (t) {
    18      case REFCOUNT_ADD_NOT_ZERO_OVF:
    19      case REFCOUNT_ADD_OVF:
    20          REFCOUNT_WARN("saturated; leaking memory");
    21          break;
    22      case REFCOUNT_ADD_UAF:
    23      case REFCOUNT_SUB_UAF:
->  25          REFCOUNT_WARN("addition on 0; use-after-free");
    25          break;
    26      case REFCOUNT_DEC_LEAK:
    27          REFCOUNT_WARN("decrement hit 0; leaking memory");
    28          break;
    29      default:
    30          REFCOUNT_WARN("unknown saturation event!?");
    31      }
    32  }

RBX = 0x2 = REFCOUNT_ADD_UAF, confirming the switch branch taken.


5. kobject_get -- lib/kobject.c:643

   636  struct kobject *kobject_get(struct kobject *kobj)
   637  {
   638      if (kobj) {
   639          if (!kobj->state_initialized)
   640              WARN(1, KERN_WARNING
   641                  "kobject: '%s' (%p): is not initialized, "
   641                  "yet kobject_get() is being called.\n",
   642               kobject_name(kobj), kobj);
-> 643          kref_get(&kobj->kref);   /* unconditional increment */
   644      }
   645      return kobj;
   646  }

kobject_get_unless_zero() (line 649) checks for zero first via
kref_get_unless_zero, but is not used here.


6. i2c_get_adapter -- drivers/i2c/i2c-core-base.c:2612

  2602  struct i2c_adapter *i2c_get_adapter(int nr)
  2603  {
  2604      struct i2c_adapter *adapter;
  2605
  2606      mutex_lock(&core_lock);
  2607      adapter = idr_find(&i2c_adapter_idr, nr);
  2608      if (!adapter)
  2609          goto exit;
  2610
  2611      if (try_module_get(adapter->owner))
->2612          get_device(&adapter->dev);   /* crash: dev refcount == 0 */
  2613      else
  2614          adapter = NULL;
  2615
  2616   exit:
  2617      mutex_unlock(&core_lock);
  2618      return adapter;
  2619  }


7. i2cdev_open -- drivers/i2c/i2c-dev.c:603

   597  static int i2cdev_open(struct inode *inode, struct file *file)
   598  {
   599      unsigned int minor = iminor(inode);
   600      struct i2c_client *client;
   601      struct i2c_adapter *adap;
   602
-> 603      adap = i2c_get_adapter(minor);
   604      if (!adap)
   605          return -ENODEV;
   ...
   618  }


Tentative Analysis

The crash is a "refcount_t: addition on 0; use-after-free" WARNING in
refcount_warn_saturate(), triggered when get_device() is called on an
I2C adapter whose struct device refcount has already reached zero.

The sequence of events:

1. A task opens /dev/i2c-N, which calls i2cdev_open(), which calls
   i2c_get_adapter(minor).

2. i2c_get_adapter() takes core_lock, calls idr_find(), and finds the
   adapter in the IDR (non-NULL).  try_module_get() succeeds.
   get_device(&adapter->dev) is then called.

3. Concurrently, i2c_del_adapter() has already called
   device_unregister(&adap->dev), which drops the device refcount to
   zero.  At this point the adapter is still in the IDR: idr_remove()
   is not called until after wait_for_completion() returns.

4. There is therefore a window where i2c_get_adapter() can find the
   adapter in the IDR and attempt get_device() on an object whose
   kobject refcount is already 0, triggering the WARNING.

The race exists because i2c_del_adapter() removes the adapter from
the IDR only *after* wait_for_completion(), which itself is called
after device_unregister() (which drops the device refcount to zero
when there is only one reference).  i2c_get_adapter() holds core_lock
for its entire body including the get_device() call, but
i2c_del_adapter() releases core_lock before calling
device_unregister(), so the two can execute concurrently.

The bug was introduced by commit 611e12ea0f12 ("i2c: core: manage i2c
bus device refcount in i2c_[get|put]_adapter", 2015), which added
get_device() to i2c_get_adapter() without reordering the idr_remove()
call in i2c_del_adapter().  Before that commit only try_module_get()
was called, so the idr_remove() ordering was inconsequential.


Potential Solution

Move the idr_remove() call in i2c_del_adapter() to before the
device_unregister() call, still under core_lock.  Once the adapter is
removed from the IDR, any concurrent i2c_get_adapter() call will
receive NULL from idr_find() and return -ENODEV.  Callers that already
obtained a device reference before the idr_remove() hold a legitimate
reference; wait_for_completion() will correctly wait for them to
release it via i2c_put_adapter().

Rough patch (against e753c16cb3dd):

  --- a/drivers/i2c/i2c-core-base.c
  +++ b/drivers/i2c/i2c-core-base.c
  @@ i2c_del_adapter
  +    /* Remove from IDR before device_unregister() to prevent a
  +     * concurrent i2c_get_adapter() from calling get_device() on a
  +     * kobject whose refcount has already reached zero.
  +     */
  +    mutex_lock(&core_lock);
  +    idr_remove(&i2c_adapter_idr, adap->nr);
  +    mutex_unlock(&core_lock);
  +
       /* wait until all references to the device are gone ... */
       init_completion(&adap->dev_released);
       device_unregister(&adap->dev);
       wait_for_completion(&adap->dev_released);
   
  -    /* free bus id */
  -    mutex_lock(&core_lock);
  -    idr_remove(&i2c_adapter_idr, adap->nr);
  -    mutex_unlock(&core_lock);
  -


More information

Oops-Analysis: http://oops.fenrus.org/reports/lkml/69e93024.a00a0220.17a17.0031.GAE_google.com/
Assisted-by: GitHub Copilot linux-kernel-oops-x86.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-04-25 21:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-22 20:31 [syzbot] [i2c?] WARNING: refcount bug in i2c_get_adapter (2) syzbot
2026-04-25 21:45 ` Arjan van de Ven

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.