Is it possible to figure Linux kernel version from a snapshot of system physical memory? - linux-kernel

I was wondering if given a snapshot of the physical memory os system running Linux OS it is possible the figure out what is the Kernel version it was running? I don't have access to the image or anything.

The kernel version is into the physical memory dump of the kernel as returned by /proc/version from the struct new_utsname defined into include/uapi/linux/utsname.h. I suggest to first try the 'strings' command on your kernel dump and try to identify part of the pattern usually returned by /proc/version.
The Linux source init/version.c define this:
const char linux_banner[] =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "#"
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"
So a search of the string "Linux version" into the dump should give you the location of the linux_banner string that contain the information returned by /proc/version.

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 to get registered filesystems list?

On debugging linux kernel 3.6.11 with - "ddd vmlinux /proc/kcore" , the "file_systems" list present in fs/filesystems.c is shown empty, containing the address 0x0 .
It is supposed to contain file_system_type structures of all the registered file systems .
Why the list is empty or where else can I see the list of registered file systems ?
Debugging the kernel is not needed for that. There is a proc API that provides the information:
cat /proc/filesystems

Profiling the memory used by linux kernel

I have linux kernel 2.6.30 on an ARM based embedded device.
I have to do some kernel memory usage profiling on the device.
I am thinking of monitoring the ps output on various kernel threads and modules while I carry out actions like wifi on/off etc.
Can you suggest me:
Which threads I need to monitor? How to monitor the kernel module memory usage?
sometimes it is useful to get the real info straight from the kernel, I have used this little C program I threw together to get real system info in an output format that is suited for the shell (it compiles down to a pretty small binary if that matters) --
#include <sys/sysinfo.h>
int main(int argc, char **argv){
struct sysinfo info;
sysinfo(&info);
printf( "UPTIME_SECONDS=%d\n"
"LOAD_1MIN=%d\n"
"LOAD_5MIN=%d\n"
"LOAD_15MIN=%d\n"
"RAM_TOT=%d\n"
"RAM_FREE=%d\n"
"MEMUSEDKB=%d\n"
"RAM_SHARED=%d\n"
"RAM_BUFFERS=%d\n"
"SWAP_TOT=%d\n"
"SWAP_FREE=%d\n"
"PROCESSES=%d\n",
info.uptime,
info.loads[0],
info.loads[1],
info.loads[2],
info.totalram,
info.freeram,
(info.totalram-info.freeram)*info.mem_unit/1024,
info.sharedram,
info.bufferram,
info.totalswap,
info.freeswap,
info.procs);
}
I use it in the shell like this:
eval `sysinfo`
BEFORERAM=$MEMUSEDKB
command &
sleep .1 #sleep value may need to be adjusted depending on command's run time
eval `sysinfo`
AFTERRAM=$MEMUSEDKB
echo RAMDELTA is $(($AFTERRAM - BEFORERAM ))

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