VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-45916

CVE-2026-45916

Description

In the Linux kernel, the following vulnerability has been resolved:

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

Using the devm_ variant for requesting IRQ _before_ the devm_ variant for allocating/registering the power_supply handle, means that the power_supply handle will be deallocated/unregistered _before_ the interrupt handler (since devm_ naturally deallocates in reverse allocation order). This means that during removal, there is a race condition where an interrupt can fire just _after_ the power_supply handle has been freed, *but* just _before_ the corresponding unregistration of the IRQ handler has run.

This will lead to the IRQ handler calling power_supply_changed() with a freed power_supply handle. Which usually crashes the system or otherwise silently corrupts the memory...

Note that there is a similar situation which can also happen during probe(); the possibility of an interrupt firing _before_ registering the power_supply handle. This would then lead to the nasty situation of using the power_supply handle *uninitialized* in power_supply_changed().

Fix this racy use-after-free by making sure the IRQ is requested _after_ the registration of the power_supply handle. Keep the old behavior of just printing a warning in case of any failures during the IRQ request and finishing the probe successfully.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A use-after-free in sbs-battery driver occurs when an IRQ fires after power_supply is freed due to devm_ allocation reverse ordering.

Vulnerability

A use-after-free vulnerability exists in the Linux kernel's sbs-battery power supply driver, present in versions where the devm_ framework is used incorrectly: the IRQ handler is registered *before* the power_supply device is allocated and registered (as noted in the official description [1]). Because devm_ automatically frees resources in the reverse order of allocation, during device removal the power_supply handle is deallocated first, while the IRQ handler remains active for a brief window. An interrupt that fires between these two events will call power_supply_changed() with a freed pointer, leading to memory corruption or a crash. A similar race exists during probe: an IRQ may fire before the power_supply handle is fully initialized, resulting in an uninitialized pointer being passed to power_supply_changed().

Exploitation

An attacker must be able to trigger device removal (or probe reordering) on a system using the sbs-battery driver, for example by physically disconnecting a Smart Battery System charger or by leveraging other means of device unbinding. The race window is small and requires precise timing; successful exploitation typically relies on repeated removal/rebind cycles or concurrent interrupt generation. No authentication or special privileges are needed if the attacker can control device hotplug events.

Impact

Successful exploitation of the use-after-free leads to a kernel memory corruption, which often results in a system crash (denial of service). In some cases, an attacker may be able to leverage the corruption for controlled memory write or read, potentially escalating to privilege escalation or arbitrary code execution at the kernel level. The exact impact depends on the kernel memory allocator state at the time of the race.

Mitigation

The fix [1] reorders the driver's probe sequence so that the IRQ is requested *after* the power_supply handle is registered, eliminating both the removal-time and probe-time races. The fix was committed to the Linux kernel stable tree as commit 82d3eb97a976c9d56bb92b241397610e57a9c629. Users should apply the patch or update to a kernel version containing this commit. No workaround is available for unpatched kernels; affected systems should be updated as soon as possible.

AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

16
8d59cf3887fb

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 7.0via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index 943c82ee978f40..43c48196c16741 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1217,6 +1199,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
ca7dd71773e4

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 5.10.252via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index b6a538ebb378fc..ee8816ce0b800f 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1131,24 +1131,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1176,6 +1158,24 @@ skip_gpio:
     		goto exit_psupply;
     	}
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
f1f472b14ad5

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 5.15.202via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index c4a95b01463aef..a633130a768df0 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
8010b745b436

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.1.165via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index c4a95b01463aef..a633130a768df0 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
2078830c32d1

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.6.128via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index cdfc8466d129b7..f30a542d4716ce 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
82d3eb97a976

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.12.75via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index a6c204c08232a5..f80edceafc3cf2 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
861dda7a9074

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.18.14via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index 943c82ee978f40..43c48196c16741 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1217,6 +1199,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
14d4dee5d8fb

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.19.4via kernel-cna
1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index 943c82ee978f40..43c48196c16741 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1217,6 +1199,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
14d4dee5d8fb

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index 943c82ee978f40..43c48196c16741 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1217,6 +1199,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
2078830c32d1

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index cdfc8466d129b7..f30a542d4716ce 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
8010b745b436

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index c4a95b01463aef..a633130a768df0 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
82d3eb97a976

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index a6c204c08232a5..f80edceafc3cf2 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
861dda7a9074

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index 943c82ee978f40..43c48196c16741 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1217,6 +1199,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
8d59cf3887fb

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index 943c82ee978f40..43c48196c16741 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1217,6 +1199,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
ca7dd71773e4

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index b6a538ebb378fc..ee8816ce0b800f 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1131,24 +1131,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1176,6 +1158,24 @@ skip_gpio:
     		goto exit_psupply;
     	}
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    
f1f472b14ad5

power: supply: sbs-battery: Fix use-after-free in power_supply_changed()

1 file changed · +18 19
  • drivers/power/supply/sbs-battery.c+18 19 modified
    diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
    index c4a95b01463aef..a633130a768df0 100644
    --- a/drivers/power/supply/sbs-battery.c
    +++ b/drivers/power/supply/sbs-battery.c
    @@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
     
     	i2c_set_clientdata(client, chip);
     
    -	if (!chip->gpio_detect)
    -		goto skip_gpio;
    -
    -	irq = gpiod_to_irq(chip->gpio_detect);
    -	if (irq <= 0) {
    -		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    -		goto skip_gpio;
    -	}
    -
    -	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    -		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    -		dev_name(&client->dev), chip);
    -	if (rc) {
    -		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    -		goto skip_gpio;
    -	}
    -
    -skip_gpio:
     	/*
     	 * Before we register, we might need to make sure we can actually talk
     	 * to the battery.
    @@ -1216,6 +1198,24 @@ skip_gpio:
     		return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
     				     "Failed to register power supply\n");
     
    +	if (!chip->gpio_detect)
    +		goto out;
    +
    +	irq = gpiod_to_irq(chip->gpio_detect);
    +	if (irq <= 0) {
    +		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
    +		goto out;
    +	}
    +
    +	rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
    +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +		dev_name(&client->dev), chip);
    +	if (rc) {
    +		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
    +		goto out;
    +	}
    +
    +out:
     	dev_info(&client->dev,
     		"%s: battery gas gauge device registered\n", client->name);
     
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Incorrect ordering of devm-managed resource allocation causes the power_supply handle to be freed before the interrupt handler is unregistered, leading to a use-after-free race."

Attack vector

An attacker who can trigger a GPIO interrupt on the SBS battery's `gpio_detect` line during driver removal can cause a use-after-free. During removal, devm resources are freed in reverse allocation order: the `power_supply` handle (allocated second) is freed before the IRQ handler (allocated first) is unregistered. If an interrupt fires in that window, `sbs_irq` calls `power_supply_changed()` with a freed `power_supply` pointer, leading to a crash or memory corruption. A similar race exists during probe: an interrupt arriving before `power_supply` registration would cause `power_supply_changed()` to use an uninitialized handle.

Affected code

The bug is in the `sbs_probe()` function in `drivers/power/supply/sbs-battery.c` [patch_id=2661383]. The original code called `devm_request_threaded_irq()` (for the GPIO-based interrupt) _before_ registering the `power_supply` device via the devm-managed power supply registration API. This ordering created a lifetime mismatch where the `power_supply` handle could be freed while the interrupt handler `sbs_irq` was still registered.

What the fix does

The patch moves the IRQ request (`devm_request_threaded_irq()`) to _after_ the `power_supply` registration [patch_id=2661383]. In the original code, the IRQ was requested first (lines removed from the top of `sbs_probe`), then the power supply was registered. Because devm unwinds in reverse order, the power supply would be freed before the IRQ was freed. By swapping the order — registering the power supply first, then requesting the IRQ — the devm teardown now frees the IRQ first, ensuring the interrupt handler cannot fire after the power supply handle is gone. The same reordering also prevents the probe-time race where an interrupt could fire on an uninitialized handle.

Preconditions

  • configThe SBS battery driver must be using a GPIO-based detect interrupt (chip->gpio_detect must be set).
  • inputThe attacker must be able to cause a GPIO interrupt on the detect line during the driver removal window (e.g., by physically manipulating the battery connection).
  • authNo authentication is required; the vulnerability is in kernel driver resource management.

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.