Re: [PATCH v2 3/3] kexec: Introduce paramters load_limit_reboot and load_limit_panic

2022-12-20 Thread Ricardo Ribalda
Hi Joel

Thanks for looking into this

On Thu, 15 Dec 2022 at 20:16, Joel Fernandes  wrote:
>
> Hi Ricardo,
>
> On Thu, Dec 08, 2022 at 05:38:02PM +0100, Ricardo Ribalda wrote:
> > Add two parameter to specify how many times a kexec kernel can be loaded.
> >
> > The sysadmin can set different limits for kexec panic and kexec reboot
> > kernels.
> >
> > The value can be modified at runtime via sysfs, but only with a value
> > smaller than the current one (except -1).
> >
> > Signed-off-by: Ricardo Ribalda 
> > ---
> >  Documentation/admin-guide/kernel-parameters.txt | 14 
> >  include/linux/kexec.h   |  2 +-
> >  kernel/kexec.c  |  2 +-
> >  kernel/kexec_core.c | 91 
> > -
> >  kernel/kexec_file.c |  2 +-
> >  5 files changed, 106 insertions(+), 5 deletions(-)
> >
> > diff --git a/Documentation/admin-guide/kernel-parameters.txt 
> > b/Documentation/admin-guide/kernel-parameters.txt
> > index 42af9ca0127e..2b37d6a20747 100644
> > --- a/Documentation/admin-guide/kernel-parameters.txt
> > +++ b/Documentation/admin-guide/kernel-parameters.txt
> > @@ -2374,6 +2374,20 @@
> >   for Movable pages.  "nn[KMGTPE]", "nn%", and "mirror"
> >   are exclusive, so you cannot specify multiple forms.
> >
> > + kexec_core.load_limit_reboot=
> > + kexec_core.load_limit_panic=
> > + [KNL]
> > + This parameter specifies a limit to the number of 
> > times
> > + a kexec kernel can be loaded.
> > + Format: 
> > + -1  = Unlimited.
> > + int = Number of times kexec can be called.
> > +
> > + During runtime, this parameter can be modified with a
> > + value smaller than the current one (but not -1).
> > +
> > + Default: -1
> > +
> >   kgdbdbgp=   [KGDB,HW] kgdb over EHCI usb debug port.
> >   Format: [,poll interval]
> >   The controller # is the number of the ehci usb debug
> > diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> > index e9e1ab5e8006..3d7d10f7187a 100644
> > --- a/include/linux/kexec.h
> > +++ b/include/linux/kexec.h
> > @@ -407,7 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage 
> > *image);
> >  extern struct kimage *kexec_image;
> >  extern struct kimage *kexec_crash_image;
> >
> > -bool kexec_load_permited(void);
> > +bool kexec_load_permited(bool crash_image);
> >
> >  #ifndef kexec_flush_icache_page
> >  #define kexec_flush_icache_page(page)
> > diff --git a/kernel/kexec.c b/kernel/kexec.c
> > index d83fc9093aff..2b0856e83fe1 100644
> > --- a/kernel/kexec.c
> > +++ b/kernel/kexec.c
> > @@ -193,7 +193,7 @@ static inline int kexec_load_check(unsigned long 
> > nr_segments,
> >   int result;
> >
> >   /* We only trust the superuser with rebooting the system. */
> > - if (!kexec_load_permited())
> > + if (!kexec_load_permited(flags & KEXEC_ON_CRASH))
>
> nit: permitted.
>
> >   return -EPERM;
> >
> >   /* Permit LSMs and IMA to fail the kexec */
> > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
> > index 18bd90ca9c99..7f9d5288b24b 100644
> > --- a/kernel/kexec_core.c
> > +++ b/kernel/kexec_core.c
> > @@ -952,13 +952,100 @@ static int __init kexec_core_sysctl_init(void)
> >  late_initcall(kexec_core_sysctl_init);
> >  #endif
> >
> > -bool kexec_load_permited(void)
> > +struct kexec_load_limit {
> > + /* Mutex protects the limit count. */
> > + struct mutex mutex;
> > + int limit;
>
> Can you not just use atomic ops for limit, and get rid of the mutex?
>
> That will simplify the code as well.

I could not find a way to use atomic_t. The operations are not just
counters, but maybe I am missing a better way to do it :)

The current operations:

- permitted():

if (param==-1) {
  return -1;
}
if (param =0)
 return -1;
param = param -1;



- paramter_set()

new_param = min(-1, new_param);

if (param == -1) {
   param = new_param;
   return
}

if (new_param == -1) {
   return -EINVAL;
}

param = min(new_param, param);

>
> > +};
> > +
> > +struct kexec_load_limit load_limit_reboot = {
> > + .mutex = __MUTEX_INITIALIZER(load_limit_reboot.mutex),
> > + .limit = -1,
> > +};
> > +
> > +struct kexec_load_limit load_limit_panic = {
> > + .mutex = __MUTEX_INITIALIZER(load_limit_panic.mutex),
> > + .limit = -1,
> > +};
> > +
> > +static int param_get_limit(char *buffer, const struct kernel_param *kp)
> >  {
> > + int ret;
> > + struct kexec_load_limit *limit = kp->arg;
> > +
> > + mutex_lock(>mutex);
> > + ret = scnprintf(buffer, PAGE_SIZE, "%i\n", limit->limit);
> > + mutex_unlock(>mutex);
> > +
> > + return ret;
> > +}
> > +
> > +static int param_set_limit(const char *buffer, const struct kernel_param 
> 

Re: [PATCH v2 3/3] kexec: Introduce paramters load_limit_reboot and load_limit_panic

2022-12-15 Thread Guilherme G. Piccoli
On 08/12/2022 13:38, Ricardo Ribalda wrote:
> Add two parameter to specify how many times a kexec kernel can be loaded.
> 
> The sysadmin can set different limits for kexec panic and kexec reboot
> kernels.
> 
> The value can be modified at runtime via sysfs, but only with a value
> smaller than the current one (except -1).
> 
> Signed-off-by: Ricardo Ribalda 
> ---

Thanks for your patches Ricardo!

Small nit in the subject: s/paramters/parameters. Just observed that
after Joel's review anyway, so kudos to him heh

Cheers,


Guilherme

___
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec


Re: [PATCH v2 3/3] kexec: Introduce paramters load_limit_reboot and load_limit_panic

2022-12-15 Thread Joel Fernandes
Hi Ricardo,

On Thu, Dec 08, 2022 at 05:38:02PM +0100, Ricardo Ribalda wrote:
> Add two parameter to specify how many times a kexec kernel can be loaded.
> 
> The sysadmin can set different limits for kexec panic and kexec reboot
> kernels.
> 
> The value can be modified at runtime via sysfs, but only with a value
> smaller than the current one (except -1).
> 
> Signed-off-by: Ricardo Ribalda 
> ---
>  Documentation/admin-guide/kernel-parameters.txt | 14 
>  include/linux/kexec.h   |  2 +-
>  kernel/kexec.c  |  2 +-
>  kernel/kexec_core.c | 91 
> -
>  kernel/kexec_file.c |  2 +-
>  5 files changed, 106 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt 
> b/Documentation/admin-guide/kernel-parameters.txt
> index 42af9ca0127e..2b37d6a20747 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -2374,6 +2374,20 @@
>   for Movable pages.  "nn[KMGTPE]", "nn%", and "mirror"
>   are exclusive, so you cannot specify multiple forms.
>  
> + kexec_core.load_limit_reboot=
> + kexec_core.load_limit_panic=
> + [KNL]
> + This parameter specifies a limit to the number of times
> + a kexec kernel can be loaded.
> + Format: 
> + -1  = Unlimited.
> + int = Number of times kexec can be called.
> +
> + During runtime, this parameter can be modified with a
> + value smaller than the current one (but not -1).
> +
> + Default: -1
> +
>   kgdbdbgp=   [KGDB,HW] kgdb over EHCI usb debug port.
>   Format: [,poll interval]
>   The controller # is the number of the ehci usb debug
> diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> index e9e1ab5e8006..3d7d10f7187a 100644
> --- a/include/linux/kexec.h
> +++ b/include/linux/kexec.h
> @@ -407,7 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage 
> *image);
>  extern struct kimage *kexec_image;
>  extern struct kimage *kexec_crash_image;
>  
> -bool kexec_load_permited(void);
> +bool kexec_load_permited(bool crash_image);
>  
>  #ifndef kexec_flush_icache_page
>  #define kexec_flush_icache_page(page)
> diff --git a/kernel/kexec.c b/kernel/kexec.c
> index d83fc9093aff..2b0856e83fe1 100644
> --- a/kernel/kexec.c
> +++ b/kernel/kexec.c
> @@ -193,7 +193,7 @@ static inline int kexec_load_check(unsigned long 
> nr_segments,
>   int result;
>  
>   /* We only trust the superuser with rebooting the system. */
> - if (!kexec_load_permited())
> + if (!kexec_load_permited(flags & KEXEC_ON_CRASH))

nit: permitted.

>   return -EPERM;
>  
>   /* Permit LSMs and IMA to fail the kexec */
> diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
> index 18bd90ca9c99..7f9d5288b24b 100644
> --- a/kernel/kexec_core.c
> +++ b/kernel/kexec_core.c
> @@ -952,13 +952,100 @@ static int __init kexec_core_sysctl_init(void)
>  late_initcall(kexec_core_sysctl_init);
>  #endif
>  
> -bool kexec_load_permited(void)
> +struct kexec_load_limit {
> + /* Mutex protects the limit count. */
> + struct mutex mutex;
> + int limit;

Can you not just use atomic ops for limit, and get rid of the mutex?

That will simplify the code as well.

> +};
> +
> +struct kexec_load_limit load_limit_reboot = {
> + .mutex = __MUTEX_INITIALIZER(load_limit_reboot.mutex),
> + .limit = -1,
> +};
> +
> +struct kexec_load_limit load_limit_panic = {
> + .mutex = __MUTEX_INITIALIZER(load_limit_panic.mutex),
> + .limit = -1,
> +};
> +
> +static int param_get_limit(char *buffer, const struct kernel_param *kp)
>  {
> + int ret;
> + struct kexec_load_limit *limit = kp->arg;
> +
> + mutex_lock(>mutex);
> + ret = scnprintf(buffer, PAGE_SIZE, "%i\n", limit->limit);
> + mutex_unlock(>mutex);
> +
> + return ret;
> +}
> +
> +static int param_set_limit(const char *buffer, const struct kernel_param *kp)
> +{
> + int ret;
> + struct kexec_load_limit *limit = kp->arg;
> + int new_val;
> +
> + ret = kstrtoint(buffer, 0, _val);
> + if (ret)
> + return ret;
> +
> + new_val = max(-1, new_val);
> +
> + mutex_lock(>mutex);
> +
> + if (new_val == -1 && limit->limit != -1) {
> + ret = -EINVAL;
> + goto done;
> + }
> +
> + if (limit->limit != -1 && new_val > limit->limit) {
> + ret = -EINVAL;
> + goto done;
> + }
> +
> + limit->limit = new_val;
> +
> +done:
> + mutex_unlock(>mutex);
> +
> + return ret;
> +}
> +
> +static const struct kernel_param_ops load_limit_ops = {
> + .get = param_get_limit,
> + .set = param_set_limit,
> 

[PATCH v2 3/3] kexec: Introduce paramters load_limit_reboot and load_limit_panic

2022-12-08 Thread Ricardo Ribalda
Add two parameter to specify how many times a kexec kernel can be loaded.

The sysadmin can set different limits for kexec panic and kexec reboot
kernels.

The value can be modified at runtime via sysfs, but only with a value
smaller than the current one (except -1).

Signed-off-by: Ricardo Ribalda 
---
 Documentation/admin-guide/kernel-parameters.txt | 14 
 include/linux/kexec.h   |  2 +-
 kernel/kexec.c  |  2 +-
 kernel/kexec_core.c | 91 -
 kernel/kexec_file.c |  2 +-
 5 files changed, 106 insertions(+), 5 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index 42af9ca0127e..2b37d6a20747 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2374,6 +2374,20 @@
for Movable pages.  "nn[KMGTPE]", "nn%", and "mirror"
are exclusive, so you cannot specify multiple forms.
 
+   kexec_core.load_limit_reboot=
+   kexec_core.load_limit_panic=
+   [KNL]
+   This parameter specifies a limit to the number of times
+   a kexec kernel can be loaded.
+   Format: 
+   -1  = Unlimited.
+   int = Number of times kexec can be called.
+
+   During runtime, this parameter can be modified with a
+   value smaller than the current one (but not -1).
+
+   Default: -1
+
kgdbdbgp=   [KGDB,HW] kgdb over EHCI usb debug port.
Format: [,poll interval]
The controller # is the number of the ehci usb debug
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index e9e1ab5e8006..3d7d10f7187a 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -407,7 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage 
*image);
 extern struct kimage *kexec_image;
 extern struct kimage *kexec_crash_image;
 
-bool kexec_load_permited(void);
+bool kexec_load_permited(bool crash_image);
 
 #ifndef kexec_flush_icache_page
 #define kexec_flush_icache_page(page)
diff --git a/kernel/kexec.c b/kernel/kexec.c
index d83fc9093aff..2b0856e83fe1 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -193,7 +193,7 @@ static inline int kexec_load_check(unsigned long 
nr_segments,
int result;
 
/* We only trust the superuser with rebooting the system. */
-   if (!kexec_load_permited())
+   if (!kexec_load_permited(flags & KEXEC_ON_CRASH))
return -EPERM;
 
/* Permit LSMs and IMA to fail the kexec */
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 18bd90ca9c99..7f9d5288b24b 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -952,13 +952,100 @@ static int __init kexec_core_sysctl_init(void)
 late_initcall(kexec_core_sysctl_init);
 #endif
 
-bool kexec_load_permited(void)
+struct kexec_load_limit {
+   /* Mutex protects the limit count. */
+   struct mutex mutex;
+   int limit;
+};
+
+struct kexec_load_limit load_limit_reboot = {
+   .mutex = __MUTEX_INITIALIZER(load_limit_reboot.mutex),
+   .limit = -1,
+};
+
+struct kexec_load_limit load_limit_panic = {
+   .mutex = __MUTEX_INITIALIZER(load_limit_panic.mutex),
+   .limit = -1,
+};
+
+static int param_get_limit(char *buffer, const struct kernel_param *kp)
 {
+   int ret;
+   struct kexec_load_limit *limit = kp->arg;
+
+   mutex_lock(>mutex);
+   ret = scnprintf(buffer, PAGE_SIZE, "%i\n", limit->limit);
+   mutex_unlock(>mutex);
+
+   return ret;
+}
+
+static int param_set_limit(const char *buffer, const struct kernel_param *kp)
+{
+   int ret;
+   struct kexec_load_limit *limit = kp->arg;
+   int new_val;
+
+   ret = kstrtoint(buffer, 0, _val);
+   if (ret)
+   return ret;
+
+   new_val = max(-1, new_val);
+
+   mutex_lock(>mutex);
+
+   if (new_val == -1 && limit->limit != -1) {
+   ret = -EINVAL;
+   goto done;
+   }
+
+   if (limit->limit != -1 && new_val > limit->limit) {
+   ret = -EINVAL;
+   goto done;
+   }
+
+   limit->limit = new_val;
+
+done:
+   mutex_unlock(>mutex);
+
+   return ret;
+}
+
+static const struct kernel_param_ops load_limit_ops = {
+   .get = param_get_limit,
+   .set = param_set_limit,
+};
+
+module_param_cb(load_limit_reboot, _limit_ops, _limit_reboot, 0644);
+MODULE_PARM_DESC(load_limit_reboot, "Maximum attempts to load a kexec reboot 
kernel");
+
+module_param_cb(load_limit_panic, _limit_ops, _limit_panic, 0644);
+MODULE_PARM_DESC(load_limit_reboot, "Maximum attempts to load a kexec panic 
kernel");
+
+bool kexec_load_permited(bool crash_image)
+{
+