1

Due to work needs I've expanded kernel version string and length of it from 64 to 128 characters to add build date, commit info and some other important for our work info. Kernel version is 3.4.112 with few device specific modifications. After that kernel fails to load at the end of booting with kernel panic:

[   38.181594] IP-Config: Complete:
[   38.184853]      device=eth0, addr=192.168.7.2, mask=255.255.248.0, gw=255.255.255.255
[   38.192849]      host=192.168.7.2, domain=, nis-domain=(none)
[   38.198636]      bootserver=192.168.3.12, rootserver=192.168.3.12, rootpath=
[   38.206047] 
[   38.207554] initramfs file system not in use. details in main.c
[   38.215749] VFS: Mounted root (ext2 filesystem) readonly on device 31:2.
[   38.227813] Freeing init memory: 140K
[   38.370775] mv643xx_eth_port mv643xx_eth_port.0: eth0: link up, 1000 Mb/s, full duplex, flow control disabled
[   38.429568] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[   38.429581] 
[   38.438796] [<c000dfc4>] (unwind_backtrace+0x0/0x108) from [<c03412cc>] (panic+0x9c/0x1f8)
[   38.447126] [<c03412cc>] (panic+0x9c/0x1f8) from [<c005f940>] (do_exit+0x7ec/0x818)
[   38.454836] [<c005f940>] (do_exit+0x7ec/0x818) from [<c005f9b4>] (do_group_exit+0x48/0xd8)
[   38.463161] [<c005f9b4>] (do_group_exit+0x48/0xd8) from [<c006c4b0>] (get_signal_to_deliver+0x344/0x5d4)
[   38.472705] [<c006c4b0>] (get_signal_to_deliver+0x344/0x5d4) from [<c000b154>] (do_notify_resume+0x88/0x520)
[   38.482599] [<c000b154>] (do_notify_resume+0x88/0x520) from [<c0009014>] (work_pending+0x24/0x28)

I've changed kernel source code in following places:

--- a/apps/linux-3.4/src/Makefile
+++ b/apps/linux-3.4/src/Makefile
@@ -995,7 +995,7 @@ prepare: prepare0
 # KERNELRELEASE can change from a few different places, meaning version.h
 # needs to be updated, so this check is forced on all builds

-uts_len := 64
+uts_len := 128
 define filechk_utsrelease.h
        if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
          echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2;    \

and

--- a/apps/linux-3.4/src/include/linux/utsname.h
+++ b/apps/linux-3.4/src/include/linux/utsname.h
@@ -11,14 +11,15 @@ struct oldold_utsname {
        char machine[9];
 };

+#define __OLD_UTS_LEN 128
-#define __NEW_UTS_LEN 64
+#define __NEW_UTS_LEN 128

 struct old_utsname {
-       char sysname[65];
-       char nodename[65];
-       char release[65];
-       char version[65];
-       char machine[65];
+       char sysname[__OLD_UTS_LEN + 1];
+       char nodename[__OLD_UTS_LEN + 1];
+       char release[__OLD_UTS_LEN + 1];
+       char version[__OLD_UTS_LEN + 1];
+       char machine[__OLD_UTS_LEN + 1];
 };

and

--- a/apps/linux-3.4/src/kernel/sys.c
+++ b/apps/linux-3.4/src/kernel/sys.c
@@ -1210,7 +1210,7 @@ static int override_release(char __user *release, size_t len)

        if (current->personality & UNAME26) {
                const char *rest = UTS_RELEASE;
-               char buf[65] = { 0 };
+               char buf[__NEW_UTS_LEN + 1] = { 0 };
                int ndots = 0;
                unsigned v;
                size_t copy;

With printk debugging I've founded code which causes kernel panic - it is piece of ASM code from arch/arm/kernel/sys_arm.c:

asm(    "add    r0, %0, %1\n\t"
    "mov    r1, %2\n\t"
    "mov    r2, %3\n\t"
    "bl memmove\n\t"    /* copy regs to top of stack */
    "mov    r8, #0\n\t" /* not a syscall */
    "mov    r9, %0\n\t" /* thread structure */
    "mov    sp, r0\n\t" /* reposition stack pointer */
    "b  ret_to_user"
    :
    : "r" (current_thread_info()),
      "Ir" (THREAD_START_SP - sizeof(regs)),
      "r" (&regs),
      "Ir" (sizeof(regs))
    : "r0", "r1", "r2", "r3", "r8", "r9", "ip", "lr", "memory");

I'm not very familiar with ASM and with kernel programming, so I 'll be very thankful for help.

Dmitriy Vinokurov
  • 365
  • 1
  • 6
  • 28
  • You want to debug why it is panic'ing or just want a way to modify kernel version shown? If you just want to know where to make changes for updating kernel version string [this post](https://stackoverflow.com/questions/28684811/how-to-change-version-string-of-the-kernel) might help. –  Jul 16 '18 at 05:59
  • @kbr, thanks for link, I know about EXTRAVERSION, but I need not only to set it, but also increase maximum version string length because standard 64 symbols is not enough. And these changes that I've made causes panic. So it's related things. – Dmitriy Vinokurov Jul 16 '18 at 06:06
  • 4
    Are you sure you didn't just make init segfault by breaking the kernel / user ABI for the `uname(2)` system call? (by changing the struct size). Its exit code of `0xb` is 11, which is the signal number for SIGSEGV. Or was `Attempted to kill init!` a result instead of a cause of the panic? – Peter Cordes Jul 16 '18 at 06:11
  • @PeterCordes, it does not seem to be true, as far as I see. Version length in libc is set to `_UTSNAME_LENGTH` which is defined as `1024` in `glibc-2.11.3/bits/utsname.h`, so it is even more than needed. – Dmitriy Vinokurov Jul 16 '18 at 09:57
  • @PeterCordes UPD: There are several `bits/utsname.h` files in `glibc`, in one that is used (not the that I mentioned in previous comment) `_UTSNAME_LENGTH` is `65`, I'll check it. – Dmitriy Vinokurov Jul 16 '18 at 10:15
  • 3
    I'm pretty sure Peter Cordes is correct. The 1024 number for `_UTSNAME_LENGTH` is only used for the stub implementation of `uname` for systems that don't support this system call. You'll need to rebuild glibc using your modified Linux kernel headers and then rebuild the init you're using with this custom version of glibc. – Ross Ridge Jul 16 '18 at 15:46
  • 1
    @PeterCordes, I've changed `_UTSNAME_LENGTH` in `glibc-2.11.3/sysdeps/unix/sysv/linux/bits/utsname.h` from `65` to `129`, rebuilt rootfs and deployed to device -- no more problems, kernel and system boot successfully. – Dmitriy Vinokurov Jul 17 '18 at 03:57
  • Please don't use such an old kernel version, linux 3.4.x is unmaintained since 20 months: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/log/?h=linux-3.4.y . Use a newer longterm kernel https://www.kernel.org/category/releases.html – Yann Droneaud Jul 17 '18 at 07:11

1 Answers1

3

You made init segfault by breaking the kernel / user ABI for the uname(2) system call (by changing the struct size/layout).

Its exit code of 0xb is 11, which is the signal number for SIGSEGV. Attempted to kill init! was the cause of the panic, not a symptom or side-effect.

As @RossRidge said in a comment:

The 1024 number for _UTSNAME_LENGTH is only used for the stub implementation of uname for systems that don't support this system call. You'll need to rebuild glibc using your modified Linux kernel headers and then rebuild the init you're using with this custom version of glibc.

Dmitry confirms that changing _UTSNAME_LENGTH from 65 to 129 in
glibc-2.11.3/sysdeps/unix/sysv/linux/bits/utsname.h
solved the problem, after rebuilding the root fs.

A less-hacky general solution is to really rebuild glibc against the updated kernel headers.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    Also note that binaries using `uname()` built against this custom version of glibc cannot be moved to another GNU/Linux distribution. – Yann Droneaud Jul 17 '18 at 07:04