Message ID | 20231025130737.2015468-1-gnstark@salutedevices.com |
---|---|
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:ce89:0:b0:403:3b70:6f57 with SMTP id p9csp2587164vqx; Wed, 25 Oct 2023 06:08:35 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGJPfE274oM0oXmclY/o4MmRyK5Mn15Z17my39N/aMbSR0c8sW97g+giqgmyRe7ouGlCYA6 X-Received: by 2002:a05:6808:4d:b0:3ae:5c89:dcc2 with SMTP id v13-20020a056808004d00b003ae5c89dcc2mr16956826oic.34.1698239315335; Wed, 25 Oct 2023 06:08:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1698239315; cv=none; d=google.com; s=arc-20160816; b=rqyoobDcYgGliNn39ded6oiTkTbbAQxwihZjv51yY8kErDjHO91VAWu6ipe6R4A0Cd zqLknTL2o/MBL+ci5AOnRCdQfZe9zWB/R8kObxfED2rzpa9yAP074Ie9fEIWkKccCLfC p7/12nWRHW3LTrfsmXpzQQQQT+TC+dD1Vq/Ul/1U5BbQFtFQEh4AiHVAZSWQq0P8vPjB b3BXOI0WVBKFsWznEvEFF1GZxSbRWULJ8znaTNRftMD9/oI0kfkfoaL8yCbzZMDUVvGm HF5bfjGMzcGQfZj1E+ZdEjO6zbfAo20pLmCZpDfriMvTY+MlHCbQrxHQTkPq7tl235PL JTAA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature:dkim-filter; bh=yGub9+Dsp9bk1acBBB0/yAlR8ZzAfw6sZjBF08zOdpU=; fh=TH/KyKkXF5LipyBG9stysnOYaFHGBRYytRmnm4H0CpA=; b=chRHukUBVF0zn+BbI4OTiRvLcjZYmV2RI9nKibhFblCDstW6gvugg38VwR1oBPcHy+ idzq0LOiBfctFn2k1Qg1mmvPckr/MvPQF3CyqaVyG0COIy/Pm7I26le4j2PqKtWR6I1N 6Igo2LUM27I0jf4zAKNbhCStEqbX0nANCb+qlJNlWnmSN69dCE59I1G5KuzMZv33BskK T3Jeoa6rIox5Ge44Bq7E7khnhXabamJgGMjI9BuRZmkU0JQHvRdIBA5/iBQLQqzzDUjE V3fcsClWaxqtY+YSGYvVYNenpzuX7R9g8C06MIOv+PPKmqBmWfLoev2Ih7jtby+deAw3 wGjg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@salutedevices.com header.s=mail header.b="s4EP/Tnf"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:3 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=salutedevices.com Received: from lipwig.vger.email (lipwig.vger.email. [2620:137:e000::3:3]) by mx.google.com with ESMTPS id d193-20020a25cdca000000b00da052e38ac7si3100711ybf.425.2023.10.25.06.08.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 25 Oct 2023 06:08:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:3 as permitted sender) client-ip=2620:137:e000::3:3; Authentication-Results: mx.google.com; dkim=pass header.i=@salutedevices.com header.s=mail header.b="s4EP/Tnf"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:3 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=salutedevices.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by lipwig.vger.email (Postfix) with ESMTP id 577BD80FD8BA; Wed, 25 Oct 2023 06:08:31 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at lipwig.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234964AbjJYNIA (ORCPT <rfc822;aposhian.dev@gmail.com> + 26 others); Wed, 25 Oct 2023 09:08:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234952AbjJYNHx (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Wed, 25 Oct 2023 09:07:53 -0400 Received: from mx1.sberdevices.ru (mx1.sberdevices.ru [37.18.73.165]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70DC5116; Wed, 25 Oct 2023 06:07:47 -0700 (PDT) Received: from p-infra-ksmg-sc-msk01 (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id 667BE10003F; Wed, 25 Oct 2023 16:07:44 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru 667BE10003F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1698239264; bh=yGub9+Dsp9bk1acBBB0/yAlR8ZzAfw6sZjBF08zOdpU=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=s4EP/TnfUb8IXrOlVO//TgpOfTSDBG+Z+BupDUdIDF4DstolYt1F8kT5getb3vo/v Bmy7SwjJb7ThjM6IhKaxIjjDZsqZonF/QV18hXnUWatQvWRYf5mA0Is2cA3hNNcK1U phiXb4HwBMu81Q05o/V3t3ENkXUzgZzw5zaHTbo06EMUPjKpXUaKxQvPmwzUsEgvyM qkcKPnKtKzHGjduuCKmuSVgfvCAkJM04Rb8aOOpc7o5AiM6v7fEt2KrwlsJ+EcEVcm 8tSPkAhUdpoFrPGRlsflj/Q3iF2v8leMoMNgKzrnZQSRIfs127bnTYk19IAP4QW8Op PkfyBfHAvf2XQ== Received: from p-i-exch-sc-m01.sberdevices.ru (p-i-exch-sc-m01.sberdevices.ru [172.16.192.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Wed, 25 Oct 2023 16:07:44 +0300 (MSK) Received: from localhost.localdomain (100.64.160.123) by p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.37; Wed, 25 Oct 2023 16:07:43 +0300 From: George Stark <gnstark@salutedevices.com> To: <pavel@ucw.cz>, <lee@kernel.org>, <vadimp@nvidia.com>, <mpe@ellerman.id.au>, <npiggin@gmail.com>, <christophe.leroy@csgroup.eu>, <gnstark@salutedevices.com> CC: <linux-leds@vger.kernel.org>, <linux-kernel@vger.kernel.org>, <linuxppc-dev@lists.ozlabs.org>, <kernel@sberdevices.ru> Subject: [PATCH 0/8] devm_led_classdev_register() usage problem Date: Wed, 25 Oct 2023 16:07:29 +0300 Message-ID: <20231025130737.2015468-1-gnstark@salutedevices.com> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Originating-IP: [100.64.160.123] X-ClientProxiedBy: p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) To p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 180883 [Oct 25 2023] X-KSMG-AntiSpam-Version: 6.0.0.2 X-KSMG-AntiSpam-Envelope-From: gnstark@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 543 543 1e3516af5cdd92079dfeb0e292c8747a62cb1ee4, {Tracking_from_domain_doesnt_match_to}, 127.0.0.199:7.1.2;d41d8cd98f00b204e9800998ecf8427e.com:7.1.1;100.64.160.123:7.1.2;p-i-exch-sc-m01.sberdevices.ru:7.1.1,5.0.1;salutedevices.com:7.1.1, FromAlignment: s, ApMailHostAddress: 100.64.160.123 X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2023/10/25 11:29:00 #22291710 X-KSMG-AntiVirus-Status: Clean, skipped X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lipwig.vger.email Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (lipwig.vger.email [0.0.0.0]); Wed, 25 Oct 2023 06:08:31 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1780732988122841782 X-GMAIL-MSGID: 1780732988122841782 |
Series |
devm_led_classdev_register() usage problem
|
|
Message
George Stark
Oct. 25, 2023, 1:07 p.m. UTC
Lots of drivers use devm_led_classdev_register() to register their led objects and let the kernel free those leds at the driver's remove stage. It can lead to a problem due to led_classdev_unregister() implementation calls led_set_brightness() to turn off the led. led_set_brightness() may call one of the module's brightness_set callbacks. If that callback uses module's resources allocated without using devm funcs() then those resources will be already freed at module's remove() callback and we may have use-after-free situation. Here is an example: module_probe() { devm_led_classdev_register(module_brightness_set_cb); mutex_init(&mutex); } module_brightness_set_cb() { mutex_lock(&mutex); do_set_brightness(); mutex_unlock(&mutex); } module_remove() { mutex_destroy(&mutex); } at rmmod: module_remove() ->mutex_destroy(&mutex); devres_release_all() ->led_classdev_unregister(); ->led_set_brightness(); ->module_brightness_set_cb(); ->mutex_lock(&mutex); /* use-after-free */ I think it's an architectural issue and should be discussed thoroughly. Some thoughts about fixing it as a start: 1) drivers can use devm_led_classdev_unregister() to explicitly free leds before dependend resources are freed. devm_led_classdev_register() remains being useful to simplify probe implementation. As a proof of concept I examined all drivers from drivers/leds and prepared patches where it's needed. Sometimes it was not as clean as just calling devm_led_classdev_unregister() because several drivers do not track their leds object at all - they can call devm_led_classdev_register() and drop the returned pointer. In that case I used devres group API. Drivers outside drivers/leds should be checked too after discussion. 2) remove led_set_brightness from led_classdev_unregister() and force the drivers to turn leds off at shutdown. May be add check that led's brightness is 0 at led_classdev_unregister() and put a warning to dmesg if it's not. Actually in many cases it doesn't really need to turn off the leds manually one-by-one if driver shutdowns whole led controller. For the last case to disable the warning new flag can be brought in e.g LED_AUTO_OFF_AT_SHUTDOWN (similar to LED_RETAIN_AT_SHUTDOWN). George Stark (8): leds: powernv: explicitly unregister LEDs at module's shutdown leds: nic78bx: explicitly unregister LEDs at module's shutdown leds: an30259a: explicitly unregister LEDs at module's shutdown leds: mlxreg: explicitly unregister LEDs at module's shutdown leds: aw200xx: explicitly unregister LEDs at module's shutdown leds: aw2013: explicitly unregister LEDs at module's shutdown leds: lp3952: explicitly unregister LEDs at module's shutdown leds: lm3532: explicitly unregister LEDs at module's shutdown drivers/leds/leds-an30259a.c | 4 ++++ drivers/leds/leds-aw200xx.c | 4 ++++ drivers/leds/leds-aw2013.c | 4 ++++ drivers/leds/leds-lm3532.c | 6 ++++++ drivers/leds/leds-lp3952.c | 5 +++++ drivers/leds/leds-mlxreg.c | 12 +++++++++++- drivers/leds/leds-nic78bx.c | 4 ++++ drivers/leds/leds-powernv.c | 7 +++++++ 8 files changed, 45 insertions(+), 1 deletion(-)
Comments
Hello Andy Could you please take a look at this patch series? I've just found your post on habr about devres API misusing and I think this is just another case. On 10/25/23 16:07, George Stark wrote: > Lots of drivers use devm_led_classdev_register() to register their led objects > and let the kernel free those leds at the driver's remove stage. > It can lead to a problem due to led_classdev_unregister() > implementation calls led_set_brightness() to turn off the led. > led_set_brightness() may call one of the module's brightness_set callbacks. > If that callback uses module's resources allocated without using devm funcs() > then those resources will be already freed at module's remove() callback and > we may have use-after-free situation. > > Here is an example: > > module_probe() > { > devm_led_classdev_register(module_brightness_set_cb); > mutex_init(&mutex); > } > > module_brightness_set_cb() > { > mutex_lock(&mutex); > do_set_brightness(); > mutex_unlock(&mutex); > } > > module_remove() > { > mutex_destroy(&mutex); > } > > at rmmod: > module_remove() > ->mutex_destroy(&mutex); > devres_release_all() > ->led_classdev_unregister(); > ->led_set_brightness(); > ->module_brightness_set_cb(); > ->mutex_lock(&mutex); /* use-after-free */ > > I think it's an architectural issue and should be discussed thoroughly. > Some thoughts about fixing it as a start: > 1) drivers can use devm_led_classdev_unregister() to explicitly free leds before > dependend resources are freed. devm_led_classdev_register() remains being useful > to simplify probe implementation. > As a proof of concept I examined all drivers from drivers/leds and prepared > patches where it's needed. Sometimes it was not as clean as just calling > devm_led_classdev_unregister() because several drivers do not track > their leds object at all - they can call devm_led_classdev_register() and drop the > returned pointer. In that case I used devres group API. > > Drivers outside drivers/leds should be checked too after discussion. > > 2) remove led_set_brightness from led_classdev_unregister() and force the drivers > to turn leds off at shutdown. May be add check that led's brightness is 0 > at led_classdev_unregister() and put a warning to dmesg if it's not. > Actually in many cases it doesn't really need to turn off the leds manually one-by-one > if driver shutdowns whole led controller. For the last case to disable the warning > new flag can be brought in e.g LED_AUTO_OFF_AT_SHUTDOWN (similar to LED_RETAIN_AT_SHUTDOWN). > > George Stark (8): > leds: powernv: explicitly unregister LEDs at module's shutdown > leds: nic78bx: explicitly unregister LEDs at module's shutdown > leds: an30259a: explicitly unregister LEDs at module's shutdown > leds: mlxreg: explicitly unregister LEDs at module's shutdown > leds: aw200xx: explicitly unregister LEDs at module's shutdown > leds: aw2013: explicitly unregister LEDs at module's shutdown > leds: lp3952: explicitly unregister LEDs at module's shutdown > leds: lm3532: explicitly unregister LEDs at module's shutdown > > drivers/leds/leds-an30259a.c | 4 ++++ > drivers/leds/leds-aw200xx.c | 4 ++++ > drivers/leds/leds-aw2013.c | 4 ++++ > drivers/leds/leds-lm3532.c | 6 ++++++ > drivers/leds/leds-lp3952.c | 5 +++++ > drivers/leds/leds-mlxreg.c | 12 +++++++++++- > drivers/leds/leds-nic78bx.c | 4 ++++ > drivers/leds/leds-powernv.c | 7 +++++++ > 8 files changed, 45 insertions(+), 1 deletion(-) >
Le 25/10/2023 à 15:07, George Stark a écrit : > Lots of drivers use devm_led_classdev_register() to register their led objects > and let the kernel free those leds at the driver's remove stage. > It can lead to a problem due to led_classdev_unregister() > implementation calls led_set_brightness() to turn off the led. > led_set_brightness() may call one of the module's brightness_set callbacks. > If that callback uses module's resources allocated without using devm funcs() > then those resources will be already freed at module's remove() callback and > we may have use-after-free situation. > > Here is an example: > > module_probe() > { > devm_led_classdev_register(module_brightness_set_cb); > mutex_init(&mutex); > } > > module_brightness_set_cb() > { > mutex_lock(&mutex); > do_set_brightness(); > mutex_unlock(&mutex); > } > > module_remove() > { > mutex_destroy(&mutex); > } > > at rmmod: > module_remove() > ->mutex_destroy(&mutex); > devres_release_all() > ->led_classdev_unregister(); > ->led_set_brightness(); > ->module_brightness_set_cb(); > ->mutex_lock(&mutex); /* use-after-free */ > > I think it's an architectural issue and should be discussed thoroughly. > Some thoughts about fixing it as a start: > 1) drivers can use devm_led_classdev_unregister() to explicitly free leds before > dependend resources are freed. devm_led_classdev_register() remains being useful > to simplify probe implementation. > As a proof of concept I examined all drivers from drivers/leds and prepared > patches where it's needed. Sometimes it was not as clean as just calling > devm_led_classdev_unregister() because several drivers do not track > their leds object at all - they can call devm_led_classdev_register() and drop the > returned pointer. In that case I used devres group API. I see no point in using a device managed function if you have to call the unregister function. All the purpose of device managed functions is to avoid having to call an unregister function at the end. > > Drivers outside drivers/leds should be checked too after discussion. > > 2) remove led_set_brightness from led_classdev_unregister() and force the drivers > to turn leds off at shutdown. May be add check that led's brightness is 0 > at led_classdev_unregister() and put a warning to dmesg if it's not. > Actually in many cases it doesn't really need to turn off the leds manually one-by-one > if driver shutdowns whole led controller. For the last case to disable the warning > new flag can be brought in e.g LED_AUTO_OFF_AT_SHUTDOWN (similar to LED_RETAIN_AT_SHUTDOWN). > > George Stark (8): > leds: powernv: explicitly unregister LEDs at module's shutdown > leds: nic78bx: explicitly unregister LEDs at module's shutdown > leds: an30259a: explicitly unregister LEDs at module's shutdown > leds: mlxreg: explicitly unregister LEDs at module's shutdown > leds: aw200xx: explicitly unregister LEDs at module's shutdown > leds: aw2013: explicitly unregister LEDs at module's shutdown > leds: lp3952: explicitly unregister LEDs at module's shutdown > leds: lm3532: explicitly unregister LEDs at module's shutdown > > drivers/leds/leds-an30259a.c | 4 ++++ > drivers/leds/leds-aw200xx.c | 4 ++++ > drivers/leds/leds-aw2013.c | 4 ++++ > drivers/leds/leds-lm3532.c | 6 ++++++ > drivers/leds/leds-lp3952.c | 5 +++++ > drivers/leds/leds-mlxreg.c | 12 +++++++++++- > drivers/leds/leds-nic78bx.c | 4 ++++ > drivers/leds/leds-powernv.c | 7 +++++++ > 8 files changed, 45 insertions(+), 1 deletion(-) >
On Wed, Oct 25, 2023 at 04:07:29PM +0300, George Stark wrote: > Lots of drivers use devm_led_classdev_register() to register their led objects > and let the kernel free those leds at the driver's remove stage. > It can lead to a problem due to led_classdev_unregister() > implementation calls led_set_brightness() to turn off the led. > led_set_brightness() may call one of the module's brightness_set callbacks. > If that callback uses module's resources allocated without using devm funcs() > then those resources will be already freed at module's remove() callback and > we may have use-after-free situation. > > Here is an example: > > module_probe() > { > devm_led_classdev_register(module_brightness_set_cb); > mutex_init(&mutex); > } > > module_brightness_set_cb() > { > mutex_lock(&mutex); > do_set_brightness(); > mutex_unlock(&mutex); > } > > module_remove() > { > mutex_destroy(&mutex); > } > > at rmmod: > module_remove() > ->mutex_destroy(&mutex); > devres_release_all() > ->led_classdev_unregister(); > ->led_set_brightness(); > ->module_brightness_set_cb(); > ->mutex_lock(&mutex); /* use-after-free */ > > I think it's an architectural issue and should be discussed thoroughly. > Some thoughts about fixing it as a start: > 1) drivers can use devm_led_classdev_unregister() to explicitly free leds before > dependend resources are freed. devm_led_classdev_register() remains being useful > to simplify probe implementation. > As a proof of concept I examined all drivers from drivers/leds and prepared > patches where it's needed. Sometimes it was not as clean as just calling > devm_led_classdev_unregister() because several drivers do not track > their leds object at all - they can call devm_led_classdev_register() and drop the > returned pointer. In that case I used devres group API. > > Drivers outside drivers/leds should be checked too after discussion. > > 2) remove led_set_brightness from led_classdev_unregister() and force the drivers > to turn leds off at shutdown. May be add check that led's brightness is 0 > at led_classdev_unregister() and put a warning to dmesg if it's not. > Actually in many cases it doesn't really need to turn off the leds manually one-by-one > if driver shutdowns whole led controller. For the last case to disable the warning > new flag can be brought in e.g LED_AUTO_OFF_AT_SHUTDOWN (similar to LED_RETAIN_AT_SHUTDOWN). NAK. Just fix the drivers by wrapping mutex_destroy() into devm, There are many doing so. You may be brave enough to introduce devm_mutex_init() somewhere in include/linux/device*
On Sat, Nov 4, 2023 at 9:17 AM George Stark <gnstark@salutedevices.com> wrote: > > Hello Andy > > Could you please take a look at this patch series? > > I've just found your post on habr about devres API misusing and I think > this is just another case. Just had a look, sorry for the delay. By quickly reading it seems to be a wrong approach (or wrong end to start solving the issue from).
Hello Andy Thanks for the review. On 11/24/23 18:28, Andy Shevchenko wrote: > On Wed, Oct 25, 2023 at 04:07:29PM +0300, George Stark wrote: >> Lots of drivers use devm_led_classdev_register() to register their led objects >> and let the kernel free those leds at the driver's remove stage. >> It can lead to a problem due to led_classdev_unregister() >> implementation calls led_set_brightness() to turn off the led. >> led_set_brightness() may call one of the module's brightness_set callbacks. >> If that callback uses module's resources allocated without using devm funcs() >> then those resources will be already freed at module's remove() callback and >> we may have use-after-free situation. >> >> Here is an example: >> >> module_probe() >> { >> devm_led_classdev_register(module_brightness_set_cb); >> mutex_init(&mutex); >> } >> >> module_brightness_set_cb() >> { >> mutex_lock(&mutex); >> do_set_brightness(); >> mutex_unlock(&mutex); >> } >> >> module_remove() >> { >> mutex_destroy(&mutex); >> } >> >> at rmmod: >> module_remove() >> ->mutex_destroy(&mutex); >> devres_release_all() >> ->led_classdev_unregister(); >> ->led_set_brightness(); >> ->module_brightness_set_cb(); >> ->mutex_lock(&mutex); /* use-after-free */ >> >> I think it's an architectural issue and should be discussed thoroughly. >> Some thoughts about fixing it as a start: >> 1) drivers can use devm_led_classdev_unregister() to explicitly free leds before >> dependend resources are freed. devm_led_classdev_register() remains being useful >> to simplify probe implementation. >> As a proof of concept I examined all drivers from drivers/leds and prepared >> patches where it's needed. Sometimes it was not as clean as just calling >> devm_led_classdev_unregister() because several drivers do not track >> their leds object at all - they can call devm_led_classdev_register() and drop the >> returned pointer. In that case I used devres group API. >> >> Drivers outside drivers/leds should be checked too after discussion. >> >> 2) remove led_set_brightness from led_classdev_unregister() and force the drivers >> to turn leds off at shutdown. May be add check that led's brightness is 0 >> at led_classdev_unregister() and put a warning to dmesg if it's not. >> Actually in many cases it doesn't really need to turn off the leds manually one-by-one >> if driver shutdowns whole led controller. For the last case to disable the warning >> new flag can be brought in e.g LED_AUTO_OFF_AT_SHUTDOWN (similar to LED_RETAIN_AT_SHUTDOWN). > > NAK. > > Just fix the drivers by wrapping mutex_destroy() into devm, There are many > doing so. You may be brave enough to introduce devm_mutex_init() somewhere > in include/linux/device* > Just one thing about mutex_destroy(). It seems like there's no single opinion on should it be called in 100% cases e.g. in remove() paths. For example in iio subsystem Jonathan suggests it can be dropped in simple cases: https://www.spinics.net/lists/linux-iio/msg73423.html So the question is can we just drop mutex_destroy() in module's remove() callback here if that mutex is needed for devm subsequent callbacks?
On Sat, 25 Nov 2023 03:47:41 +0300 George Stark <gnstark@salutedevices.com> wrote: > Hello Andy > > Thanks for the review. > > On 11/24/23 18:28, Andy Shevchenko wrote: > > On Wed, Oct 25, 2023 at 04:07:29PM +0300, George Stark wrote: > >> Lots of drivers use devm_led_classdev_register() to register their led objects > >> and let the kernel free those leds at the driver's remove stage. > >> It can lead to a problem due to led_classdev_unregister() > >> implementation calls led_set_brightness() to turn off the led. > >> led_set_brightness() may call one of the module's brightness_set callbacks. > >> If that callback uses module's resources allocated without using devm funcs() > >> then those resources will be already freed at module's remove() callback and > >> we may have use-after-free situation. > >> > >> Here is an example: > >> > >> module_probe() > >> { > >> devm_led_classdev_register(module_brightness_set_cb); > >> mutex_init(&mutex); > >> } > >> > >> module_brightness_set_cb() > >> { > >> mutex_lock(&mutex); > >> do_set_brightness(); > >> mutex_unlock(&mutex); > >> } > >> > >> module_remove() > >> { > >> mutex_destroy(&mutex); > >> } > >> > >> at rmmod: > >> module_remove() > >> ->mutex_destroy(&mutex); > >> devres_release_all() > >> ->led_classdev_unregister(); > >> ->led_set_brightness(); > >> ->module_brightness_set_cb(); > >> ->mutex_lock(&mutex); /* use-after-free */ > >> > >> I think it's an architectural issue and should be discussed thoroughly. > >> Some thoughts about fixing it as a start: > >> 1) drivers can use devm_led_classdev_unregister() to explicitly free leds before > >> dependend resources are freed. devm_led_classdev_register() remains being useful > >> to simplify probe implementation. > >> As a proof of concept I examined all drivers from drivers/leds and prepared > >> patches where it's needed. Sometimes it was not as clean as just calling > >> devm_led_classdev_unregister() because several drivers do not track > >> their leds object at all - they can call devm_led_classdev_register() and drop the > >> returned pointer. In that case I used devres group API. > >> > >> Drivers outside drivers/leds should be checked too after discussion. > >> > >> 2) remove led_set_brightness from led_classdev_unregister() and force the drivers > >> to turn leds off at shutdown. May be add check that led's brightness is 0 > >> at led_classdev_unregister() and put a warning to dmesg if it's not. > >> Actually in many cases it doesn't really need to turn off the leds manually one-by-one > >> if driver shutdowns whole led controller. For the last case to disable the warning > >> new flag can be brought in e.g LED_AUTO_OFF_AT_SHUTDOWN (similar to LED_RETAIN_AT_SHUTDOWN). > > > > NAK. > > > > Just fix the drivers by wrapping mutex_destroy() into devm, There are many > > doing so. You may be brave enough to introduce devm_mutex_init() somewhere > > in include/linux/device* > > > > Just one thing about mutex_destroy(). It seems like there's no single > opinion on should it be called in 100% cases e.g. in remove() paths. > For example in iio subsystem Jonathan suggests it can be dropped in > simple cases: https://www.spinics.net/lists/linux-iio/msg73423.html > > So the question is can we just drop mutex_destroy() in module's remove() > callback here if that mutex is needed for devm subsequent callbacks? I've never considered it remotely critical. The way IIO works means that things have gone pretty horribly wrong in the core if you managed to access a mutex after the unwind of devm_iio_device_register() has completed but sure, add a devm_mutex_init() and I'd happily see that adopted in IIO for consistency and to avoid answering questions on whether it is necessary to call mutex_destroy() My arguement has always eben that if line after(ish) a mutex_destroy() is going to either free the memory it's in, or make it otherwise inaccessible (IIO is proxying accesses via chardevs if there are open so should ensure they never hit the driver) then it's pointless and messy to call mutex_destroy(). devm_mutex_init() gets rid of that mess.. Jonathan >
On Sat, Nov 25, 2023 at 03:47:41AM +0300, George Stark wrote: > On 11/24/23 18:28, Andy Shevchenko wrote: > > On Wed, Oct 25, 2023 at 04:07:29PM +0300, George Stark wrote: > > > Lots of drivers use devm_led_classdev_register() to register their led objects > > > and let the kernel free those leds at the driver's remove stage. > > > It can lead to a problem due to led_classdev_unregister() > > > implementation calls led_set_brightness() to turn off the led. > > > led_set_brightness() may call one of the module's brightness_set callbacks. > > > If that callback uses module's resources allocated without using devm funcs() > > > then those resources will be already freed at module's remove() callback and > > > we may have use-after-free situation. > > > > > > Here is an example: > > > > > > module_probe() > > > { > > > devm_led_classdev_register(module_brightness_set_cb); > > > mutex_init(&mutex); > > > } > > > > > > module_brightness_set_cb() > > > { > > > mutex_lock(&mutex); > > > do_set_brightness(); > > > mutex_unlock(&mutex); > > > } > > > > > > module_remove() > > > { > > > mutex_destroy(&mutex); > > > } > > > > > > at rmmod: > > > module_remove() > > > ->mutex_destroy(&mutex); > > > devres_release_all() > > > ->led_classdev_unregister(); > > > ->led_set_brightness(); > > > ->module_brightness_set_cb(); > > > ->mutex_lock(&mutex); /* use-after-free */ > > > > > > I think it's an architectural issue and should be discussed thoroughly. > > > Some thoughts about fixing it as a start: > > > 1) drivers can use devm_led_classdev_unregister() to explicitly free leds before > > > dependend resources are freed. devm_led_classdev_register() remains being useful > > > to simplify probe implementation. > > > As a proof of concept I examined all drivers from drivers/leds and prepared > > > patches where it's needed. Sometimes it was not as clean as just calling > > > devm_led_classdev_unregister() because several drivers do not track > > > their leds object at all - they can call devm_led_classdev_register() and drop the > > > returned pointer. In that case I used devres group API. > > > > > > Drivers outside drivers/leds should be checked too after discussion. > > > > > > 2) remove led_set_brightness from led_classdev_unregister() and force the drivers > > > to turn leds off at shutdown. May be add check that led's brightness is 0 > > > at led_classdev_unregister() and put a warning to dmesg if it's not. > > > Actually in many cases it doesn't really need to turn off the leds manually one-by-one > > > if driver shutdowns whole led controller. For the last case to disable the warning > > > new flag can be brought in e.g LED_AUTO_OFF_AT_SHUTDOWN (similar to LED_RETAIN_AT_SHUTDOWN). > > > > NAK. > > > > Just fix the drivers by wrapping mutex_destroy() into devm, There are many > > doing so. You may be brave enough to introduce devm_mutex_init() somewhere > > in include/linux/device* > > Just one thing about mutex_destroy(). It seems like there's no single > opinion on should it be called in 100% cases e.g. in remove() paths. > For example in iio subsystem Jonathan suggests it can be dropped in simple > cases: https://www.spinics.net/lists/linux-iio/msg73423.html > > So the question is can we just drop mutex_destroy() in module's remove() > callback here if that mutex is needed for devm subsequent callbacks? mutex_destroy() makes sense when debugging mutexes. It's harmless to drop, but will make life harder to one who is trying to debug something there...