lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CALkUMdR4y6r9AwdX5_jnhaRHuDhkqvnxWOj_8rr3VSBOmqjo9Q@mail.gmail.com>
Date: Tue, 15 Oct 2024 13:27:33 +0530
From: Vimal Agrawal <avimalin@...il.com>
To: linux-kernel@...r.kernel.org, gregkh@...uxfoundation.org, arnd@...db.de
Subject: Re: [PATCH v2] misc: misc_minor_alloc to use ida for all dynamic/misc
 dynamic minors

Hi Greg,

Added commit that this fixed under "Fixes:" in commit log
As this was not causing any failure in any functions, I tested it by
looking at WARN in logs.
I wrote a very basic kunit for testing misc_register as I could not
find any tests for it.

I was hoping to fail misc_register if someone passes minor value in
the range of dynamic and misc dynamic minor but I do see at least one
case where PSMOUSE_MINOR(1)
is passed. Unless we decide to change the range of dynamic minors from
0 -127 to 1-127 but I am not sure if there are other such cases so to
be safer this patch is allowing
callers to pass minor in the range of dynamic /misc dynamic minors as
was the case earlier.

Thanks,
Vimal

On Tue, Oct 15, 2024 at 12:32 PM Vimal Agrawal <avimalin@...il.com> wrote:
>
> misc_minor_alloc was allocating id using ida for minor only in case of
> MISC_DYNAMIC_MINOR but misc_minor_free was always freeing ids
> using ida_free causing a mismatch and following warn:
> > > WARNING: CPU: 0 PID: 159 at lib/idr.c:525 ida_free+0x3e0/0x41f
> > > ida_free called for id=127 which is not allocated.
> > > <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> ...
> > > [<60941eb4>] ida_free+0x3e0/0x41f
> > > [<605ac993>] misc_minor_free+0x3e/0xbc
> > > [<605acb82>] misc_deregister+0x171/0x1b3
>
> misc_minor_alloc is changed to allocate id from ida for all minors
> falling in the range of dynamic/ misc dynamic minors
>
> Fixes: 0ad35fed618c ("char: misc: Increase the maximum number of dynamic misc devices to 1048448")
> Signed-off-by: Vimal Agrawal <vimal.agrawal@...hos.com>
> ---
>  drivers/char/misc.c   | 35 +++++++++++++++++-----
>  lib/Kconfig.debug     | 11 +++++++
>  lib/Makefile          |  1 +
>  lib/test_misc_minor.c | 67 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 107 insertions(+), 7 deletions(-)
>  create mode 100644 lib/test_misc_minor.c
>
> diff --git a/drivers/char/misc.c b/drivers/char/misc.c
> index 541edc26ec89..9d0cd3459b4f 100644
> --- a/drivers/char/misc.c
> +++ b/drivers/char/misc.c
> @@ -63,16 +63,30 @@ static DEFINE_MUTEX(misc_mtx);
>  #define DYNAMIC_MINORS 128 /* like dynamic majors */
>  static DEFINE_IDA(misc_minors_ida);
>
> -static int misc_minor_alloc(void)
> +static int misc_minor_alloc(int minor)
>  {
>         int ret;
>
> -       ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL);
> -       if (ret >= 0) {
> -               ret = DYNAMIC_MINORS - ret - 1;
> -       } else {
> -               ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
> +       if (minor == MISC_DYNAMIC_MINOR) {
> +               /* allocate free id */
> +               ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL);
> +               if (ret >= 0) {
> +                       ret = DYNAMIC_MINORS - ret - 1;
> +               } else {
> +                       ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
>                                       MINORMASK, GFP_KERNEL);
> +               }
> +       } else {
> +               /* specific minor, check if it is in dynamic or misc dynamic range  */
> +               if (minor < DYNAMIC_MINORS) {
> +                       minor = DYNAMIC_MINORS - minor - 1;
> +                       ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL);
> +               } else if (minor > MISC_DYNAMIC_MINOR) {
> +                       ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL);
> +               } else {
> +                       /* case of non-dynamic minors, no need to allocate id */
> +                       ret = 0;
> +               }
>         }
>         return ret;
>  }
> @@ -219,7 +233,7 @@ int misc_register(struct miscdevice *misc)
>         mutex_lock(&misc_mtx);
>
>         if (is_dynamic) {
> -               int i = misc_minor_alloc();
> +               int i = misc_minor_alloc(misc->minor);
>
>                 if (i < 0) {
>                         err = -EBUSY;
> @@ -228,6 +242,7 @@ int misc_register(struct miscdevice *misc)
>                 misc->minor = i;
>         } else {
>                 struct miscdevice *c;
> +               int i;
>
>                 list_for_each_entry(c, &misc_list, list) {
>                         if (c->minor == misc->minor) {
> @@ -235,6 +250,12 @@ int misc_register(struct miscdevice *misc)
>                                 goto out;
>                         }
>                 }
> +
> +               i = misc_minor_alloc(misc->minor);
> +               if (i < 0) {
> +                       err = -EBUSY;
> +                       goto out;
> +               }
>         }
>
>         dev = MKDEV(MISC_MAJOR, misc->minor);
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 7315f643817a..5a5d27284e0a 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2488,6 +2488,17 @@ config TEST_RHASHTABLE
>  config TEST_IDA
>         tristate "Perform selftest on IDA functions"
>
> +config TEST_MISC_MINOR
> +       tristate "Basic misc minor Kunit test" if !KUNIT_ALL_TESTS
> +       depends on KUNIT
> +       default KUNIT_ALL_TESTS
> +       help
> +         Kunit test for the misc minor.
> +         It tests misc minor functions for dynamic and misc dynamic minor.
> +         This include misc_xxx functions
> +
> +         If unsure, say N.
> +
>  config TEST_PARMAN
>         tristate "Perform selftest on priority array manager"
>         depends on PARMAN
> diff --git a/lib/Makefile b/lib/Makefile
> index 773adf88af41..631d73f96f76 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -68,6 +68,7 @@ obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
>  obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o
>  obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
>  obj-$(CONFIG_TEST_IDA) += test_ida.o
> +obj-$(CONFIG_TEST_MISC_MINOR) += test_misc_minor.o
>  obj-$(CONFIG_TEST_UBSAN) += test_ubsan.o
>  CFLAGS_test_ubsan.o += $(call cc-disable-warning, vla)
>  CFLAGS_test_ubsan.o += $(call cc-disable-warning, unused-but-set-variable)
> diff --git a/lib/test_misc_minor.c b/lib/test_misc_minor.c
> new file mode 100644
> index 000000000000..bcec3fb1c46a
> --- /dev/null
> +++ b/lib/test_misc_minor.c
> @@ -0,0 +1,67 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <kunit/test.h>
> +#include <kunit/test-bug.h>
> +#include <linux/module.h>
> +#include <linux/miscdevice.h>
> +
> +/* dynamic minor (2) */
> +static struct miscdevice dev_dynamic_minor = {
> +        .minor  = 2,
> +        .name   = "dev_dynamic_minor",
> +};
> +
> +/* static minor (LCD_MINOR) */
> +static struct miscdevice dev_static_minor = {
> +        .minor  = LCD_MINOR,
> +        .name   = "dev_static_minor",
> +};
> +
> +/* misc dynamic minor */
> +static struct miscdevice dev_misc_dynamic_minor = {
> +        .minor  = MISC_DYNAMIC_MINOR,
> +        .name   = "dev_misc_dynamic_minor",
> +};
> +
> +static void kunit_dynamic_minor(struct kunit *test)
> +{
> +       int ret;
> +
> +       ret=misc_register(&dev_dynamic_minor);
> +       KUNIT_EXPECT_EQ(test, 0, ret);
> +       KUNIT_EXPECT_EQ(test, 2, dev_dynamic_minor.minor);
> +       misc_deregister(&dev_dynamic_minor);
> +}
> +
> +static void kunit_static_minor(struct kunit *test)
> +{
> +       int ret;
> +
> +       ret=misc_register(&dev_static_minor);
> +       KUNIT_EXPECT_EQ(test, 0, ret);
> +       KUNIT_EXPECT_EQ(test, LCD_MINOR, dev_static_minor.minor);
> +       misc_deregister(&dev_static_minor);
> +}
> +
> +static void kunit_misc_dynamic_minor(struct kunit *test)
> +{
> +       int ret;
> +
> +       ret=misc_register(&dev_misc_dynamic_minor);
> +       KUNIT_EXPECT_EQ(test, 0, ret);
> +       misc_deregister(&dev_misc_dynamic_minor);
> +}
> +
> +static struct kunit_case test_cases[] = {
> +       KUNIT_CASE(kunit_dynamic_minor),
> +       KUNIT_CASE(kunit_static_minor),
> +       KUNIT_CASE(kunit_misc_dynamic_minor),
> +       {}
> +};
> +
> +static struct kunit_suite test_suite = {
> +       .name = "misc_minor_test",
> +       .test_cases = test_cases,
> +};
> +kunit_test_suite(test_suite);
> +
> +MODULE_LICENSE("GPL");
> --
> 2.17.1
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ