How can I determine the build/version of Linux kernel 'uImage'? - linux-kernel

I'm trying to track down a kernel binary; is there a way to determine the version (build string) of a Linux 'uImage' binary?
Running
strings uImage
piped into various trailing grep statements leads me to think I'm dealing with a compressed image...

According to kernel's format specification, here's C code:
kver.c
#include <stdio.h>
int main(int argc, char** argv){
if (argc > 1){
FILE* f = fopen(argv[1], "r");
short offset = 0;
char str[128];
if(f){
fseek(f, 0x20E, SEEK_SET);
fread(&offset, 2, 1, f);
fseek(f, offset + 0x200, SEEK_SET);
fread(str, 128, 1, f);
str[127] = '\0';
printf("%s\n", str);
fclose(f);
return 0;
}else {
return 2;
}
} else {
printf("use: kver [kernel image file]\n");
return 1;
}
}
compile and run:
gcc -o kver kver.c
./kver /boot/vmlinux-something

To find out what version of Linux is compiled, use the strings utility on the uncompressed vmlinux image.
For example:
strings linux-src/build/build-generic/vmlinux|grep "Linux version"
Sample output:
Linux version 3.2.0-56-generic (root#puerto-cayo) (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #86 SMP Fri Nov 1 10:24:18 EDT 2013 (Ubuntu 3.2.0-56.86-generic 3.2.51)

I just realized, the kernels I have immediate access to do have the version string stored uncompressed amongst the headers. strings uImage | grep 2.6 ought to be good enough for any 2.6 kernel which covers pretty much everything in the last 5+ years).
(original answer follows)
It's theoretically possible, but not entirely trivial.
Modern Linux kernel versions use a format called bzImage (for x86/x86_64, YMMV on other platforms). It actually consists of an ELF header and some other minutia (like a bit of decompression code) followed by, yes, a compressed image of the actual kernel.
Traditionally, the compression algorithm was zlib (contrary to popular misconception, 'bzImage' did not stand for "bzipped image", but for "big zImage" -- the original zImage format not being able to handle large kernels), though versions after 2.6.30 also support bzip2 and LZMA.
What you'll probably have to do is determine exactly where the compressed data starts (sorry, can't help you there, but trial and error might work), and write a bit of code to run it through the library for whichever compression algorithm is in use.

Try file uImage. It might identify the file format if it is a commonly known compression format. Other than that, the strings utility is probably the best one for this task.

This will output the kernel version and the localversion string (if any was set at build time) on a bzimage:
strings bzimage |grep -E "^[1-4]\.[0-9][0-9]*\.[0-9][0-9]*" |awk '{print $1}' |head -1
I've tested it on kernel versions 3 and 4 ... but it should also work on previous versions too.
strings vmlinuz |grep -E "^[1-4]\.[0-9][0-9]*\.[0-9][0-9]*" |awk '{print $1}' |head -1
4.4.5
strings vmlinux |grep -E "^[1-4]\.[0-9][0-9]*\.[0-9][0-9]*" |awk '{print $1}' |head -1
3.2.45-smp
If you have uImage you will haveto remove the "^" or it will not match anything
strings uImage |grep -E "[1-4]\.[0-9][0-9]*\.[0-9][0-9]*" |head -1
Linux-3.0.76

I am not sure however you might try uname -a may be this is what you want.

If it is a kernel for x86, it has the version in the header. See Documentation/x86/boot.txt (look at the kernel_version field).
I do not know if the same is true for other architectures (that header is x86-specific).

Related

How do I find out a program version from a core dump? Can I write it there myself?

I have a core file, but I am uncertain which version of the program produced it. When I use the file command, I get only the binary name, not the version.
% file core.20200730-1203
core.20200730-1203: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from 'qdrouterd -c /tmp/qdrouterd.json', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: '/usr/sbin/qdrouterd', platform: 'x86_64'
I can try to give my debugger multiple binaries in turn that I guess are close in version, and see what works and what doesn't.
I believe that the solution is to put a string constant with the version into the program code. Core dumps contain the program code, because it is loaded into memory for execution, and therefore I should be able to recover it using the strings command.
Currently, the program contains the following, where QPID_DISPATCH_VERSION is a preprocessor macro.
qd_log(router->log_source, QD_LOG_INFO, "Version: %s", QPID_DISPATCH_VERSION);
I am able to get to it, with
% strings core.20200730-1203 | grep -A3 -B3 "Version: "
Activating management agent on $_management_internal
router
Router Engine Instantiated: id=router-default-0 instance=1596103149 max_routers=128
Version: 1.13.0-SNAPSHOT
Router started in Interior mode, area=0 id=router-default-0
Container Name: router-default-0
Milan
but this is probably just an accident, a log line which was still present in the memory at the moment of crash.
What is a reliable way to encode and recover the version information?

Is the sys_call_table read protected in 4.8 kernel?

I use the simple sys_call_table rewrite to
log all execve calls in a system.
When moving to Ubuntu 16.10 with a 4.8 kernel this
mechanism suddenly stopped to work. In 16.04 with
a 4.6 kernel it was working.
1: write_cr0 (read_cr0 () & (~ 0x10000));
2: original_execve = (void *)syscall_table[__NR_execve];
3: syscall_table[__NR_execve] = (unsigned long)&new_execve;
4: write_cr0 (read_cr0 () | 0x10000);
The page fault already happens when reading the old entry, that is line 2.
To retrive the sys_call_table address I use:
sudo cat /boot/System.map-`uname -r` | grep -e '\ssys_call_table' | awk '{ print $1}' )"
Code is from: https://github.com/eiselekd/shinterposer/tree/master/mod
Does anyone know what happened? Maybe some
protection mechanism has been introduced?
There seem to be Address Space Layout Randomization (kASLR) on the syscall table taking
place by default in the 4.8 kernel. When declaring the sys_call_table symbol as exported and linking against it directly from a module the address for sys_call_table is changing for each boot.
The address from /boot/System.map-xxx is useless.
To disable kaslr in ubuntu 16.10 kernel 4.8 one can add
nokaslr
to the kernel command line.

How can I get the builder name of the linux kernel

When the linux kernel booting up,it will print the kernel version and builder, and toolchain infomation. Just like below:
Booting Linux on physical CPU 0
Linux version 3.4.24 (whobuilderthis#cl-builder23)
So how to get the builder whobuilderthis string (using shell)? Where does it store?
Thanks in advance.
You could query /proc/version which should contain the builder string.
shell#android:/ $ cat /proc/version
Linux version 3.0.31-g9f818de (android-build#vpbs1.mtv.corp.google.com) (gcc version 4.6.x-google 20120106 (prerelease) (GCC) ) #1 SMP PREEMPT Wed Nov 28 11:20:29 PST 2012
dmesg gives the kernel log, so you should be able to grep/sed it from there:
dmesg | grep 'Linux version ' | sed 's/[^(]*(\([^)]*\)).*/\1/'
(There are smarter ways of doing this.)
According to Documentation/kbuild/kbuild.rst:
KBUILD_BUILD_USER, KBUILD_BUILD_HOST
These two variables allow to override the user#host string displayed during
boot and in /proc/version. The default value is the output of the commands
whoami and host, respectively.
So "/proc/version" will output the result of current running kernel.
If you want to change the content, you need override the above 2 vars on your kernel build machine.

How to find the format of a disk volume

I am updating a backup utility I have written and have on the Mac App store.
In a Macintosh Cocoa application, how do I find how a disk volume is formatted? The only official thing I find, is doing a GetResourceValue: for 'NSURLVolumeLocalizedFormatDescriptionKey', but that is language dependent.
My utility does not support volumes formatted for FAT32. My utility needs to do special handling for XSan drives.
statfs(2) will give you a non-localized name:
struct statfs volinfo;
if(statfs("/path/to/your/volume", &volinfo) != 0)
{
perror("statfs");
return -1;
}
fprintf(stderr, "%s\n", volinfo.f_fstypename);
See /System/Library/Filesystems for the names that will be returned in f_fstypename.
This question has been answered but I'll throw my 2 cents in...
/sbin/mount | grep acfs | awk '{print $3}'
This outputs
/Volumes/XsanVolumeName1
/Volumes/XsanVolumeName2

Getting U-boot's Version from Userspace

Does anyone know of a way to get U-boot version installed from userspace? There is the fw_printenv command that provides access to U-boot's environment variables, but not the version.
If U-boot is located in mtd0, you can get version info as follows:
root#SUPERWIFI:/proc# strings /dev/mtd0 | grep U-Boot
U-Boot 1.1.4-g1c8343c8-dirty (Feb 28 2014 - 13:56:54)
U-Boot
Now running in RAM - U-Boot at: %08lx
Just an update for this.
In our version of U-Boot we changed the code for main_loop() in main.c to this:
#ifdef CONFIG_VERSION_VARIABLE
char *oldver=getenv("ver");
if(oldver==0 ||strcmp(oldver,version_string))
{
setenv("ver", version_string); /* set version variable */
saveenv();
}
#endif /* CONFIG_VERSION_VARIABLE */
So setenv/saveenv is only called, if needed by an update.
In our firmware we added
/sbin/fw_printenv -n ver > /var/config/u-boot.ver
to make the u-boot version public available.
There's no defined way to do this. Once Linux boots, u-boot is no longer running and it's RAM is reclaimed for Linux's use. Linux doesn't even know about u-boot. Nor does it have to have been booted by u-boot.
If you really want to do this, the only way to do it is to add the u-boot version to the kernel's command line, write code to scan the u-boot image in flash for it's version, or something even nastier.
An alternative solution is to read the version directly from the u-boot binary file (can be even embedded in an image file containing other binaries as well like e.g. the first stage bootloader) with e.g. mmcblk0boot0 as partition (of device mmcblk0) the bootloader resides in:
sudo grep -a --null-data U-Boot /dev/mmcblk0boot0
Site note: Does work not only for Arch Linux but e.g. Ubuntu as well.
In my devices UBoot automatically creates a "ver" environment variable containing its version:
U-Boot > printenv
baudrate=115200
ethact=FEC ETHERNET
ethaddr=24-db-ad-00-00-08
bootdelay=3
bootcmd=bootm fc080000 - fc060000
bootargs=console=ttyCPM0,115200n8 rdinit=/sbin/init
stdin=serial
stdout=serial
stderr=serial
ver=U-Boot 2009.03-svn9684 (Mar 08 2010 - 17:08:32)
Environment size: 253/131068 bytes
U-Boot >
I don't use fw_printenv, but I would imagine that this variable gets passed along as well. Maybe you already have something similar in your system?
UPDATE (5/23/2012):
I added fw_printenv to my linux image and can confirm that I do see the "ver" variable:
[root#ST600 /]# fw_printenv
baudrate=115200
ethact=FEC ETHERNET
ethaddr=24-db-ad-00-00-08
stdin=serial
stdout=serial
stderr=serial
ver=U-Boot 2009.03-svn9684 (Mar 11 2010 - 09:43:08)
bootcmd=bootm fc080000 - fc060000
bootdelay=3
bootargs=console=ttyCPM0,115200n8 rdinit=/sbin/init panic=10 mem=32m
[root#ST600 /]#
Try to read uboot version this way:
Find uboot partition, eg. for MTD device:
cat /proc/mtd
For /dev/mtd5:
cat /dev/mtd5 | hexdump -C -n 64
You can't rely on fw_printenv if you want to know u-boot version.
fw_printenv just looks for the printenv partition and dumps its data. So it's OK for normal variables, but it's not OK for the "ver" variable, which is dynamic, and whose value is initialized by u-boot when it boots. The value of this variable doesn't remain after u-boot exit, except if you manually save it to environment.
For example, on my board, if I print the "ver" variable from u-boot prompt:
U-Boot > printenv ver
ver=U-Boot 2009.11-00393-g5ca9497-dirty (Nov 26 2012 - 11:08:44)
This is the real version of u-boot, coming from u-boot itself.
Now, if I boot my board and use fw_printenv:
el#board # fw_printenv | grep ver=
ver=U-Boot 2009.11-00323-gbcc6e0e (Sep 21 2012 - 11:07:19)
As you can see, it's different. Because it happens that I have a "ver" variable defined in my environment. And it doesn't match the real u-boot version.
Of course, I could go back to u-boot, use "saveenv" to update the "ver" value in the environment. Then the two values would match. But then, I should always update the environment after changing u-boot.
So, my conclusion is that using fw_printenv to get u-boot version is definitely not a good idea.
If u-boot is residing in an MTD partition then this will work:
U_BOOT_VER=$(for part in `grep u-boot-[01] /proc/mtd | cut -f 1 -d ':'`; do strings /dev/${part} | grep "^U-Boot.*("; break; done)

Resources