wrong report of needed kernel upgrade if kernel name is too long
When the kernel version string is too long, needrestart falsely reports that the kernels needs ABI upgrade.
needrestart needs a better way to parse the kernel version string from the kernel file.
How to see the problem (with my kernel):
/usr/sbin/needrestart -bkvvvvvvvvvv
[...]
[Kernel] Linux: kernel release 6.1.42-syshawk-amd64, kernel version #6086+bookworm SMP PREEMPT_DYNAMIC Sat Nov 18 18:57:15 UTC 2023
Failed to load NeedRestart::Kernel::kFreeBSD: [Kernel/kFreeBSD] Not running on GNU/kFreeBSD!
[Kernel/Linux] /boot/vmlinuz-6.1.42-syshawk-amd64 => 6.1.42-syshawk-amd64 (root@runner-q6tz9kj-project-23-concurrent-0) #6086+bookworm SMP PREEMPT_DYNAMIC Sat Nov 18 18:57:15 UTC 20 [6.1.42-syshawk-amd64]
[Kernel/Linux] Expected linux version: 6.1.42-syshawk-amd64
NEEDRESTART-KCUR: 6.1.42-syshawk-amd64
NEEDRESTART-KEXP: 6.1.42-syshawk-amd64
NEEDRESTART-KSTA: 2
If you look at the version string in the kernel file, you'll read:
strings /boot/vmlinuz-6.1.42-syshawk-amd64 |grep '6.1.42'
6.1.42-syshawk-amd64 (root@runner-q6tz9kj-project-23-concurrent-0) #6086+bookworm SMP PREEMPT_DYNAMIC Sat Nov 18 18:57:15 UTC 2023
6.1.42-syshawk-amd64 (root@runner-q6tz9kj-project-23-concurrent-0) (gcc (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #6086+bookworm SMP PREEMPT_DYNAMIC Sat Nov 18 18:57:15 UTC 2023
The first line is the one grabbed by needrestart (see file needrestart/perl/lib/NeedRestart/Kernel/Linux.pm function nr_linux_version_x86($$)).
This function hardcodes a max length of the kernel string of "128" bytes read from the file: https://github.com/liske/needrestart/blob/280c1aeaff28a7f1ff1f38e7427e938a7e3579fd/perl/lib/NeedRestart/Kernel/Linux.pm#L71
As you can see in my example, the version string of the kernel is 130 bytes, more than 128.
The documentation for this string (https://www.kernel.org/doc/html/v6.1/x86/boot.html, look for "kernel version") only says that the string is NUL-terminated.
The hardcoded max length of "128" should be increased, or another way to parse this string should be chosen (but I don't know the best way to do it).
Doubling the buffer size as suggested by @jaycci fixed the false positive in Rocky Linux 9.3 (Blue Onyx) for me. It's based on RHEL. My currently running kernel is called /boot/vmlinuz-5.14.0-362.13.1.el9_3.x86_64. Here is some output after monkeypatching:
# /usr/sbin/needrestart -bkvvvvvvvvvv
[main] eval /etc/needrestart/needrestart.conf
[main] needrestart v3.6
[main] running in root mode
[main] systemd detected
NEEDRESTART-VER: 3.6
[Kernel] Linux: kernel release 5.14.0-362.13.1.el9_3.x86_64, kernel version #1 SMP PREEMPT_DYNAMIC Wed Dec 13 14:07:45 UTC 2023
Failed to load NeedRestart::Kernel::kFreeBSD: [Kernel/kFreeBSD] Not running on GNU/kFreeBSD!
[Kernel/Linux] /boot/vmlinuz-5.14.0-362.13.1.el9_3.x86_64 => 5.14.0-362.13.1.el9_3.x86_64 ([email protected]) #1 SMP PREEMPT_DYNAMIC Wed Dec 13 14:07:45 UTC 2023 [5.14.0-362.13.1.el9_3.x86_64]*
[Kernel/Linux] /boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64 => 5.14.0-362.8.1.el9_3.x86_64 ([email protected]) #1 SMP PREEMPT_DYNAMIC Wed Nov 8 17:36:32 UTC 2023 [5.14.0-362.8.1.el9_3.x86_64]
[Kernel/Linux] /boot/vmlinuz-5.14.0-284.30.1.el9_2.x86_64 => 5.14.0-284.30.1.el9_2.x86_64 ([email protected]) #1 SMP PREEMPT_DYNAMIC Sat Sep 16 09:55:41 UTC 2023 [5.14.0-284.30.1.el9_2.x86_64]
[Kernel/Linux] /boot/vmlinuz-0-rescue-27326f61465d413b9d1e91c582c7d28f => 5.14.0-362.8.1.el9_3.x86_64 ([email protected]) #1 SMP PREEMPT_DYNAMIC Wed Nov 8 17:36:32 UTC 2023 [5.14.0-362.8.1.el9_3.x86_64]
[Kernel/Linux] /boot/vmlinuz-0-rescue-e9cdc240366d4c94b251b55d2cfed1e0 => 5.14.0-284.11.1.el9_2.x86_64 ([email protected]) #1 SMP PREEMPT_DYNAMIC Tue May 9 17:09:15 UTC 2023 [5.14.0-284.11.1.el9_2.x86_64]
[Kernel/Linux] using RPM version sorting
[Kernel/Linux] Expected linux version: 5.14.0-362.13.1.el9_3.x86_64
NEEDRESTART-KCUR: 5.14.0-362.13.1.el9_3.x86_64
NEEDRESTART-KEXP: 5.14.0-362.13.1.el9_3.x86_64
NEEDRESTART-KSTA: 1
Thanks for the analysis.
I've increased the read to 512 bytes. That should work for most (all?) setups in the field while not making the code not more complex as needed.