Background: we have an ILI2511 touch controller which raises an interrupt when touch movement is detected. Then the host polls the touch controller via I2C. During EMC testing, the touch controller might fire many interrupts and report wrong finger positions. Nevertheless the kernel should never crash. Here is the relevant code snippets:
Init:
error = devm_request_threaded_irq(dev, client->irq, NULL, ili251x_irq, IRQF_ONESHOT, client->name, data);
Bottom half:
static irqreturn_t ili251x_irq(int irq, void *irq_data)
{
struct ili251x_data *data = irq_data;
struct i2c_client *client = data->client;
struct touchdata touchdata;
int error;
error = ili251x_read_reg(client, REG_TOUCHDATA,
&touchdata,
sizeof(touchdata) -
sizeof(struct finger)*TOUCHDATA2_FINGERS);
/* more code */
if (!error)
ili251x_report_events(data, &touchdata);
else
dev_err(&client-\>dev, "Unable to get touchdata, err = %d\\n", error);
return IRQ_HANDLED;
}
ili251x_read_reg() uses the i2c controller.
I found no array overflow or pointer issues related to stack variables.
Still under EMC heavy fire I'm getting a crash. I added a crash dump further down.
I wonder if the information I'm getting through the crash dump could be used the track down / circle in the issue? For example what does "ili251x_irq+0x200/0x2e4" mean? Is this some code pointer / data pointer referenced in a map file? I assume the stack protector is only active before returning to the caller function.
Example:
Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ili251x_irq+0x200/0x2e4
[ 691.053700] 000: CPU0: stopping
[ 691.056854] 000: CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 5.4.106-rt54-ge578cc0824 #1
[ 691.066197] 000: Hardware name: Generic DRA74X (Flattened Device Tree)
[ 691.072749] 000: Backtrace:
[ 691.075634] 000:
[ 691.077561] 000: [<c0b93090>] (dump_backtrace) from [<c0b93408>] (show_stack+0x20/0x24)
[ 691.085606] 000: r7:c120dd44 r6:60000193 r5:00000000 r4:c12996e4
[ 691.091718] 000: [<c0b933e8>] (show_stack) from [<c0ba0d04>] (dump_stack+0x98/0xac)
[ 691.099408] 000: [<c0ba0c6c>] (dump_stack) from [<c0210798>] (handle_IPI+0x404/0x47c)
[ 691.107275] 000: r7:c120dd44 r6:00000004 r5:c129ebc4 r4:c12a8270
[ 691.113387] 000: [<c0210394>] (handle_IPI) from [<c0202340>] (gic_handle_irq+0x9c/0xa0)
[ 691.121428] 000: r10:c12a8000 r9:c1201ed0 r8:fa213000 r7:fa212000 r6:fa21200c r5:c125a574
[ 691.129722] 000: r4:c120df34
[ 691.132694] 000: [<c02022a4>] (gic_handle_irq) from [<c0201a78>] (__irq_svc+0x58/0xa0)
[ 691.140643] 000: Exception stack(0xc1201ed0 to 0xc1201f18)
[ 691.146148] 000: 1ec0: 00000000 0041cd04 00000000 c022879c
[ 691.154793] 000: 1ee0: c1200000 c120d730 00000000 c120d778 c129e63d c105ea48 c12a8000 c1201f2c
[ 691.163437] 000: 1f00: c1201f0c c1201f20 c02283fc c0209b34 a0000013 ffffffff
[ 691.170513] 000: r9:c1200000 r8:c129e63d r7:c1201f04 r6:ffffffff r5:a0000013 r4:c0209b34
[ 691.178719] 000: [<c0209b04>] (arch_cpu_idle) from [<c0ba713c>] (default_idle_call+0x3c/0x48)
[ 691.187282] 000: [<c0ba7100>] (default_idle_call) from [<c026ced8>] (do_idle+0xe4/0x150)
[ 691.195407] 000: [<c026cdf4>] (do_idle) from [<c026d26c>] (cpu_startup_entry+0x28/0x2c)
[ 691.203444] 000: r9:c105ea48 r8:00000001 r7:c12a8000 r6:00000000 r5:00000002 r4:000000ce
[ 691.211649] 000: [<c026d244>] (cpu_startup_entry) from [<c0ba0ee4>] (rest_init+0xd4/0xdc)
[ 691.219859] 000: [<c0ba0e10>] (rest_init) from [<c1000b88>] (arch_call_rest_init+0x18/0x1c)
[ 691.228249] 000: r5:00000001 r4:c12a8054
[ 691.232268] 000: [<c1000b70>] (arch_call_rest_init) from [<c10010e0>] (start_kernel+0x4dc/0x51c)
[ 691.241091] 000: [<c1000c04>] (start_kernel) from [00000000>] (0x0)
[ 691.247478] 001: ---[ end Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ili251x_irq+0x200/0x2e4 ]---
[ 691.259201] 001: ------------[ cut here ]------------
We have the chip ILI2511. The driver which I'm describing is from here: ili251x.
I'm using rt kernel 5.4.y and have to stay on this version.
I tried upstream driver (https://elixir.bootlin.com/linux/v5.4.225/source/drivers/input/touchscreen/ili210x.c) but it does not work: it generates input data but when I touch a button the webbrowser, nothing happens.
Typical input queue with ili251x.c driver running:
hexdump /dev/input/event0
0000000 9ae4 3fae 6874 0003 0003 0039 0006 0000
0000010 9ae4 3fae 6874 0003 0003 0035 1730 0000
0000020 9ae4 3fae 6874 0003 0003 0036 213f 0000
0000030 9ae4 3fae 6874 0003 0001 014a 0001 0000
0000040 9ae4 3fae 6874 0003 0003 0000 1730 0000
Typical input queue with (non-working) ili210x.c driver running:
0000000 53a0 3fae f15d 0002 0003 0039 0008 0000
0000010 53a0 3fae f15d 0002 0003 0035 1535 0000
0000020 53a0 3fae f15d 0002 0003 0036 1767 0000
0000030 53a0 3fae f15d 0002 0001 014a 0001 0000
0000040 53a0 3fae f15d 0002 0003 0000 1535 0000
0000050 53a0 3fae f15d 0002 0003 0001 1767 0000
I have not yet analyzed this stream.
I looked at (https://elixir.bootlin.com/linux/v5.15.82/source/drivers/input/touchscreen/ilitek_ts_i2c.c), but this one does not support ILI2511 according to compatibility list.
There is also a driver on github: (https://github.com/NewhavenDisplay/ILI2511-Ilitek-CTP-Drivers/tree/main/Linux%20-%20Ubuntu%2010.04~16.04/ilitek_limv5_9_0_1), which is I have not tried so far.
**
[ 105.823895] BUG: unable to handle kernel paging request at ffffffffc06ed026
[ 105.823899] PGD 13c80e067 P4D 13c80e067 PUD 13c810067 PMD 12f1d0067 PTE 0
[ 105.823901] Oops: 0010 [#1] SMP NOPTI
[ 105.823903] CPU: 2 PID: 2935 Comm: bash Tainted: G OE 4.19.67-2018202030 #7
[ 105.823904] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020
[ 105.823907] RIP: 0010:0xffffffffc06ed026
[ 105.823910] Code: Bad RIP value.
[ 105.823910] RSP: 0018:ffffb129843cbf28 EFLAGS: 00010286
[ 105.823911] RAX: 0000000000000001 RBX: 0000000000000000 RCX: ffff8e4e001cb900
[ 105.823912] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8e4e2918f2d8
[ 105.823913] RBP: ffffb129843cbf28 R08: 0000000000000000 R09: 0000000000000000
[ 105.823913] R10: ffffb129843cbe98 R11: 0000000000000000 R12: ffffb129843cbf58
[ 105.823914] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[ 105.823915] FS: 00007fd974ed2700(0000) GS:ffff8e4e3de80000(0000) knlGS:0000000000000000
[ 105.823915] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 105.823916] CR2: ffffffffc06ecffc CR3: 00000000b5d0e000 CR4: 0000000000340ee0
[ 105.823932] Call Trace:
[ 105.823938] do_syscall_64+0x5a/0x110
[ 105.823941] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 105.823942] RIP: 0033:0x7fd9745c6360
[ 105.823943] Code: 0b 31 c0 48 83 c4 08 e9 ae fe ff ff 48 8d 3d 27 b4 09 00 e8 b2 1e 02 00 66 90 83 3d e9 23 2d 00 00 75 10 b8 00 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 5e de 01 00 48 89 04 24
[ 105.823944] RSP: 002b:00007ffeb6b5eb98 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
[ 105.823945] RAX: ffffffffffffffda RBX: 00007fd9748938e0 RCX: 00007fd9745c6360
[ 105.823946] RDX: 0000000000000001 RSI: 00007ffeb6b5eba7 RDI: 0000000000000000
[ 105.823946] RBP: 00000000004d7d4a R08: 00007fd974895770 R09: 00007fd974ed2700
[ 105.823947] R10: 662f37362e39312e R11: 0000000000000246 R12: 000000000045f7d0
[ 105.823947] R13: 0000000000000001 R14: 0000000000000000 R15: 00007ffeb6b5ed60
[ 105.823948] Modules linked in: rfcomm bnep snd_ens1371 snd_ac97_codec gameport ac97_bus btusb btrtl snd_pcm crct10dif_pclmul snd_seq_midi snd_seq_midi_event crc32_pclmul ghash_clmulni_intel snd_rawmidi vmw_balloon pcbc snd_seq snd_seq_device snd_timer btbcm btintel snd bluetooth aesni_intel aes_x86_64 crypto_simd cryptd glue_helper input_leds joydev serio_raw soundcore ecdh_generic i2c_piix4 mac_hid vmw_vsock_vmci_transport vsock vmw_vmci parport_pc ppdev lp parport autofs4 hid_generic usbhid hid vmwgfx ttm drm_kms_helper mptspi mptscsih syscopyarea sysfillrect mptbase sysimgblt fb_sys_fops drm psmouse e1000 scsi_transport_spi ahci libahci pata_acpi [last unloaded: ftracehooking]
[ 105.823975] CR2: ffffffffc06ed026
[ 105.823976] ---[ end trace 2530693e2a17bef8 ]---
[ 105.823977] RIP: 0010:0xffffffffc06ed026
[ 105.823978] Code: Bad RIP value.
[ 105.823979] RSP: 0018:ffffb129843cbf28 EFLAGS: 00010286
[ 105.823980] RAX: 0000000000000001 RBX: 0000000000000000 RCX: ffff8e4e001cb900
[ 105.823980] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8e4e2918f2d8
[ 105.823981] RBP: ffffb129843cbf28 R08: 0000000000000000 R09: 0000000000000000
[ 105.823981] R10: ffffb129843cbe98 R11: 0000000000000000 R12: ffffb129843cbf58
[ 105.823982] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[ 105.823983] FS: 00007fd974ed2700(0000) GS:ffff8e4e3de80000(0000) knlGS:0000000000000000
[ 105.823983] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 105.823984] CR2: ffffffffc06ecffc CR3: 00000000b5d0e000 CR4: 0000000000340ee0
[ 105.829428] BUG: unable to handle kernel paging request at ffffffffc06ed026
[ 105.829433] PGD 13c80e067 P4D 13c80e067 PUD 13c810067 PMD 12f1d0067 PTE 0
[ 105.829439] Oops: 0010 [#2] SMP NOPTI
[ 105.829442] CPU: 1 PID: 1024 Comm: in:imklog Tainted: G D OE 4.19.67-2018202030 #7
[ 105.829444] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020
[ 105.829450] RIP: 0010:0xffffffffc06ed026
[ 105.829455] Code: Bad RIP value.
[ 105.829456] RSP: 0018:ffffb12981b6bf28 EFLAGS: 00010286
[ 105.829459] RAX: 0000000000000ea7 RBX: 0000000000000000 RCX: 0000000000000000
[ 105.829460] RDX: ffff8e4e0003ae00 RSI: 0000000000000000 RDI: ffff8e4d979eb200
[ 105.829461] RBP: ffffb12981b6bf28 R08: 0000000000000000 R09: 0000000000000000
[ 105.829463] R10: ffffb12981b6be98 R11: ffff8e4e3d806e80 R12: ffffb12981b6bf58
[ 105.829464] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[ 105.829466] FS: 00007f3d4182d700(0000) GS:ffff8e4e3de40000(0000) knlGS:0000000000000000
[ 105.829468] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 105.829469] CR2: ffffffffc06ecffc CR3: 0000000134a30000 CR4: 0000000000340ee0
[ 105.829496] Call Trace:
[ 105.829505] do_syscall_64+0x5a/0x110
[ 105.829510] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 105.829512] RIP: 0033:0x7f3d43c7c51d
[ 105.829515] Code: be 20 00 00 75 10 b8 00 00 00 00 0f 05 48 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 4e fc ff ff 48 89 04 24 b8 00 00 00 00 0f 05 <48> 8b 3c 24 48 89 c2 e8 97 fc ff ff 48 89 d0 48 83 c4 08 48 3d 01
[ 105.829516] RSP: 002b:00007f3d4180c580 EFLAGS: 00000293 ORIG_RAX: 0000000000000000
[ 105.829518] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f3d43c7c51d
[ 105.829520] RDX: 0000000000001fa0 RSI: 00007f3d4180cda0 RDI: 0000000000000004
[ 105.829521] RBP: 00000000011c8320 R08: 0000000000000000 R09: 0000000000000000
[ 105.829522] R10: 00007f3d4180c3d0 R11: 0000000000000293 R12: 00007f3d4180cda0
[ 105.829524] R13: 0000000000001fa0 R14: 0000000000001f9f R15: 00007f3d4180ce98
[ 105.829526] Modules linked in: rfcomm bnep snd_ens1371 snd_ac97_codec gameport ac97_bus btusb btrtl snd_pcm crct10dif_pclmul snd_seq_midi snd_seq_midi_event crc32_pclmul ghash_clmulni_intel snd_rawmidi vmw_balloon pcbc snd_seq snd_seq_device snd_timer btbcm btintel snd bluetooth aesni_intel aes_x86_64 crypto_simd cryptd glue_helper input_leds joydev serio_raw soundcore ecdh_generic i2c_piix4 mac_hid vmw_vsock_vmci_transport vsock vmw_vmci parport_pc ppdev lp parport autofs4 hid_generic usbhid hid vmwgfx ttm drm_kms_helper mptspi mptscsih syscopyarea sysfillrect mptbase sysimgblt fb_sys_fops drm psmouse e1000 scsi_transport_spi ahci libahci pata_acpi [last unloaded: ftracehooking]
[ 105.829632] CR2: ffffffffc06ed026
[ 105.829635] ---[ end trace 2530693e2a17bef9 ]---
[ 105.829638] RIP: 0010:0xffffffffc06ed026
[ 105.829641] Code: Bad RIP value.
[ 105.829643] RSP: 0018:ffffb129843cbf28 EFLAGS: 00010286
[ 105.829644] RAX: 0000000000000001 RBX: 0000000000000000 RCX: ffff8e4e001cb900
[ 105.829646] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8e4e2918f2d8
[ 105.829647] RBP: ffffb129843cbf28 R08: 0000000000000000 R09: 0000000000000000
[ 105.829648] R10: ffffb129843cbe98 R11: 0000000000000000 R12: ffffb129843cbf58
[ 105.829649] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[ 105.829651] FS: 00007f3d4182d700(0000) GS:ffff8e4e3de40000(0000) knlGS:0000000000000000
[ 105.829653] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 105.829654] CR2: ffffffffc06ecffc CR3: 0000000134a30000 CR4: 0000000000340ee0
os2018202030#ubuntu:~$**
I learning operating systems. I made a system call hooking and I found that it has a problem with removing it.
Although the system call hooking I made works fine. But when I remove the module from the kernel, it gives this kind of error message. I assume this kind of error is related to the page size of "syscall_table", but I can't find any relation between "syscall_table" and the address that the error message gave me. (I printed syscall_table address, gave me an address starting with 0000XXXXXX.)
those are the header files that I include.
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/kallsyms.h>
#include <linux/syscalls.h>
#include <asm/syscall_wrapper.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/namei.h>
#include <linux/sched.h>
those are codes that I've written.
#include "./ftracehooking.h"
#define __NR_ftrace 336 //trace system call identifier
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jiyong Park");
MODULE_DESCRIPTION("ftrace hook");
MODULE_VERSION("0.1");
/*
trace variables
*/
int read_count = 0;
int read_bytes = 0;
int write_count = 0;
int write_bytes = 0;
int open_count = 0;
char open_file[NAME_MAX] = {0 };
int close_count = 0;
int lseek_count = 0;
/*
make trace variables accessable from dynamically inserted modules
*/
EXPORT_SYMBOL(read_count);
EXPORT_SYMBOL(read_bytes);
EXPORT_SYMBOL(write_count);
EXPORT_SYMBOL(write_bytes);
EXPORT_SYMBOL(open_count);
EXPORT_SYMBOL(open_file);
EXPORT_SYMBOL(close_count);
EXPORT_SYMBOL(lseek_count);
void **syscall_table; //pointer to syscall table
static asmlinkage int (* orig_ftrace)(const struct pt_regs *reg); //a pointer to original syscall
static asmlinkage int hook_ftrace(const struct pt_regs *reg) //a ftrace hooking syscall
{
pid_t pid = reg->di; //get first argument of the pt_regs structure
if(pid != 0) //if current process is parent process whose pid is not 0
{
/*
initialize variables
*/
read_count = 0;
read_bytes = 0;
write_count = 0;
write_bytes = 0;
open_count = 0;
open_file[0] = '\0';
close_count = 0;
lseek_count = 0;
printk(KERN_INFO "OS Assignment2 ftrace [%d] Start\n", pid); //print kernel message
}
else
{
/*
if it is child process whose pid is 0, print kernel message below
we can get current file name from task_struct *current
*/
printk(KERN_INFO "[2018202030] %s file[%s] start [x] read - %d / written - %d\n", current->comm, open_file, read_bytes, write_bytes);
printk(KERN_INFO "open[%d] close[%d] read[%d] write[%d] lseek[%d]\n", open_count, close_count, read_count, write_count, lseek_count);
printk(KERN_INFO "OS Assignment2 ftrace [%d] End\n", pid);
}
return orig_ftrace(reg); //call original ftrace syscall and return its return value
}
/*
get read and write permission at address
*/
void make_rw(void *addr)
{
unsigned int level;
pte_t *pte = lookup_address((u64)addr, &level); //get page table entry of address
if(pte->pte &~ _PAGE_RW) //if there is no write permission on the address
pte->pte |= _PAGE_RW; //turn on read write permission
}
/*
retrieve read only permission at address
*/
void make_ro(void *addr)
{
unsigned int level;
pte_t *pte = lookup_address((u64)addr, &level); //get page table entry of address
pte->pte = pte->pte &~ _PAGE_RW; //eliminate write permission
}
static int __init hooking_init(void)
{
syscall_table = (void **)kallsyms_lookup_name("sys_call_table"); //get syscall table entry
make_rw(syscall_table); //get page write permission
orig_ftrace = syscall_table[__NR_ftrace]; //store original ftrace syscall
syscall_table[__NR_ftrace] = hook_ftrace; //hook a user defined syscall
make_ro(syscall_table); //eliminate page write permission
return 0;
}
static void __exit hooking_exit(void)
{
make_rw(syscall_table); //get page write permission
syscall_table[__NR_ftrace] = orig_ftrace; //restore pre-defined syscall
make_ro(syscall_table); //eliminate page write permission
}
module_init(hooking_init); //insert module
module_exit(hooking_exit); //exit module
#include "./ftracehooking.h"
#define __NR_ftrace 336
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_lseek 8
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jiyong Park");
MODULE_DESCRIPTION("io trace hook");
MODULE_VERSION("0.1");
void **syscall_table; //pointer to syscall table
/*
external trace variables
*/
extern int read_count;
extern int read_bytes;
extern int write_count;
extern int write_bytes;
extern int open_count;
extern char open_file[NAME_MAX];
extern int close_count;
extern int lseek_count;
/*
pointers to original syscall
*/
static asmlinkage long (*orig_read)(const struct pt_regs *);
static asmlinkage long (*orig_write)(const struct pt_regs *);
static asmlinkage long (*orig_open)(const struct pt_regs *);
static asmlinkage long (*orig_close)(const struct pt_regs *);
static asmlinkage long (*orig_lseek)(const struct pt_regs *);
static asmlinkage long ftrace_read(const struct pt_regs *reg) //read syscall hook
{
read_bytes += reg->dx; //get third argument of the pt_regs structure
++read_count; //increase read count
return orig_read(reg); //call original read syscall and return its return value
}
static asmlinkage long ftrace_write(const struct pt_regs *reg) //write syscall hook
{
write_bytes += reg->dx; //get third argument of the pt_regs structure
++write_count; //increase write count
return orig_write(reg); //call original write syscall and return its return value
}
static asmlinkage long ftrace_open(const struct pt_regs *reg) //open syscall hook
{
char __user *pathname = (char *)reg->di; //get third argument from pt_regs
strncpy_from_user(open_file, pathname, NAME_MAX); //string copy null byte aware
++open_count; //increase open count
return orig_open(reg); //call original open syscall and return its return value
}
static asmlinkage long ftrace_close(const struct pt_regs *reg) //close syscall hook
{
++close_count; //increase close count
return orig_close(reg); //call original close syscall and return its return value
}
static asmlinkage long ftrace_lseek(const struct pt_regs *reg) //lseek syscall hook
{
++lseek_count; //increase lseek count
return orig_lseek(reg); //call original lseek syscall and return its return value
}
/*
get read and write permission at address
*/
/*
void make_rw(void *addr)
{
unsigned int level;
pte_t *pte = lookup_address((u64)addr, &level); //get page table entry of address
if(pte->pte &~ _PAGE_RW) //if there is no write permission on the address
pte->pte |= _PAGE_RW; //turn on read write permission
}
*/
/*
retrieve read only permission at address
*/
/*
void make_ro(void *addr)
{
unsigned int level;
pte_t *pte = lookup_address((u64)addr, &level); //get page table entry of address
pte->pte = pte->pte &~ _PAGE_RW; //eliminate write permission
}
*/
static int __init hooking_init(void)
{
syscall_table = (void **)kallsyms_lookup_name("sys_call_table"); //get syscall table entry
//make_rw(syscall_table);
write_cr0(read_cr0() & (~0x10000)); //get page write permission
/*
store original syscalls
*/
orig_read = syscall_table[__NR_read];
orig_write = syscall_table[__NR_write];
orig_open = syscall_table[__NR_open];
orig_close = syscall_table[__NR_close];
orig_lseek = syscall_table[__NR_lseek];
/*
hook a user defined syscall
*/
syscall_table[__NR_read] = ftrace_read;
syscall_table[__NR_write] = ftrace_write;
syscall_table[__NR_open] = ftrace_open;
syscall_table[__NR_close] = ftrace_close;
syscall_table[__NR_lseek] = ftrace_lseek;
write_cr0(read_cr0() | 0x10000);
return 0;
}
static void __exit hooking_exit(void)
{
/*
restore pre-defined syscall
*/
write_cr0(read_cr0() & (~0x10000));
syscall_table[__NR_read] = orig_read;
syscall_table[__NR_write] = orig_write;
syscall_table[__NR_open] = orig_open;
syscall_table[__NR_close] = orig_close;
syscall_table[__NR_lseek] = orig_lseek;
write_cr0(read_cr0() | 0x10000);
//make_ro(syscall_table); //eliminate page write permission
}
module_init(hooking_init); //insert module
module_exit(hooking_exit); //exit module
can you guys give me an idea of how to solve this problem?
I'm developing a homebrew os and I can't figure out how to switch from my homebrew bootloader to my homebrew kernel.
I do not know how it works
I know it starts with memory, but I don't know what number it starts with
I've been told that I can just look at the minix source, but when I parse it from the iso, it doesn't tell me anything at all, all it tells me is the configuration of the linux directory.
I've been trying to figure it out for a week, but nothing has come up.
I'm sorry if I'm not trying hard enough.
And since there didn't seem to be any similar questions, I thought I'd ask you a question
I'll show you a well commented minimal example of jumping to a C++ kernel I wrote so maybe you can go from there and write your own. I work on Linux Ubuntu 20.
In your home directory create a folder named OS and create a file named kernel.cpp in that folder. Place the following content in that file:
void map_framebuffer(){
unsigned long* page_directory_table_pointer = (unsigned long*) 0xb018;
*page_directory_table_pointer = 0x1e00f;
unsigned long* page_table_pointer = (unsigned long*) 0x1e000;
/*
This is the actual address of the framebuffer in QEMU
for the video mode I set up in boot.asm.
In this case it is hardcoded. You may want to actually get this from the VBE structure.
The VBE structure is placed at 0x7e00 in memory by the boot.asm routine.
*/
unsigned long framebuffer_address = (unsigned long) 0xfd00000f;
for (unsigned int i = 0; i < 512; i++){
*page_table_pointer = framebuffer_address;
framebuffer_address += 0x1000;
page_table_pointer++;
}
}
void main(){
map_framebuffer();
/*
I made sure that the framebuffer is mapped to adress 0x600000 in the map_framebuffer() function.
You may want to identity map it instead or map it somewhere else. You'll then have to
calculate page table offsets and stuff.
*/
unsigned char* framebuffer_pointer = (unsigned char*)0x600000;
//Make a few pixels become white. Each pixel is 3 bytes RGB.
for (unsigned int i = 0; i < 10000; i++)
*(framebuffer_pointer + i) = 0xff;
asm volatile(
"halt:\n\t"
"hlt\n\t"
"jmp halt\n\t");
}
/*
Memory map of kernel
7e00 - 8000 -> VBE INFO structure
8000 - 9000 -> paging.bin (booting asm code)
9000 - a000 -> pml4
a000 - b000 -> pdpt
b000 - c000 -> pdt
1b000 - 1c000 -> pt1 (kernel identity mapped pages)
1c000 - 1d000 -> pt2 (kernel identity mapped pages)
1d000 - 1e000 -> pt3 (kernel identity mapped pages)
1e000 - 1f000 -> pt4 (mapped to the framebuffer, only 2MB are mapped to the framebuffer which could take more than this)
30000 - 80000 -> kernel.elf (temporary kernel file)
80000 -> kernel stack (growing downward)
*/
Now create a file named boot.asm in the same directory and write the following content into it:
org 0x7c00
bits 16
;Set the video mode to VBE graphics mode for being able to draw onto the screen
jmp get_vbe_info
error:
mov ah, 0x0e
mov al, 'e'
int 0x10
hlt
get_vbe_info:
mov ax, 0x4f01 ;c0 00 00 00
mov cx, 0x118
xor bx, bx
mov es, bx
mov di, 0x7e00
int 0x10
cmp ax, 0x004f
jne error
set_video_mode:
mov ax, 0x4f02
mov bx, 0x4118
int 0x10
cmp ax, 0x004f
jne error
;Set up a real mode stack
mov ax, 0x00
mov ss, ax
mov sp, 0x7c00
;Load the second stage bootloader at 0x8000
mov ah, 0x00 ;reset drive
int 0x13
xor ax, ax
mov es, ax
mov bx, 0x8000 ;es:bx = 0x0000:0x8000 = 0x8000
mov ah, 0x02 ;read sector function
mov al, 0x09 ;read 9 sectors
mov ch, 0x00 ;cylinder 0
mov dh, 0x00 ;head 0
mov cl, 0x02 ;start from sector 2
int 0x13
;Load the cpp kernel at 0x30000
mov ah, 0x00
int 0x13
mov ax, 0x3000
mov es, ax
xor bx, bx ;es:bx = 0x3000:0x0000 = 0x3000 * 0x10 + 0x0 = 0x30000
mov ah, 0x02 ;read sector function
mov al, 0x3c ;read 60 sectors to load the whole file
mov ch, 0x00 ;cylinder 0
mov dh, 0x00 ;head 0
mov cl, 0x0a ;start from sector 10 (because this is where lies the ELF CPP kernel in the disk.img we created with dd)
int 0x13
xor ax, ax
mov ds, ax
;Set up a protected mode stack
mov ax, 0x10 ;10000b = 10 for segment selector 2 (data)
mov ss, ax
mov sp, 0x7c00
cli
lgdt[gdtr]
;Enable protected mode
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x08:protectedMode ;0x08 = 1000b, 1 for segment selector
;0 for gdt not ldt and 00 for privilege
bits 32
protectedMode:
mov ax, 0x10
mov ds, ax
;Jump to 0x8000 (the second stage bootloader)
jmp 0x08:0x8000
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF ;limit 0-15
dw 0x0 ;base 0-15
db 0x0 ;base 16-23
db 10011010b ;pr, privi (2), s, ex, dc, rw, ac
db 11001111b ;gr, sz, limit 16-19
db 0x0 ;base 24-31
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdtr:
dw 24
dd gdt_start
times 510 - ($-$$) db 0
dw 0xAA55
Now create a third file named paging.asm and place the following into it:
org 0x8000
bits 32
;Set up paging
mov eax, 0x00009008
mov cr3, eax
pml4t:
mov dword [0x9000], 0x0000a00f
mov dword [0x9004], 0x0
pdpt:
mov dword [0xa000], 0x0000b00f
mov dword [0xa004], 0x0
pdt:
mov dword [0xb000], 0x0001b00f
mov dword [0xb004], 0x0
mov dword [0xb008], 0x0001c00f
mov dword [0xb00c], 0x0
mov dword [0xb010], 0x0001d00f
mov dword [0xb014], 0x0
pt:
mov edx, 0x3
mov eax, 0x200
mov ebx, 0x0000000f
mov ecx, 0x1b000
next_table:
next_entry:
mov dword [ecx], ebx
add ecx, 0x4
mov dword [ecx], 0x0
add ebx, 0x1000 ;add 4096 to the adress pointed to by ebx (the next physical page)
add ecx, 0x4
sub eax, 0x1
cmp eax, 0x0
jne next_entry
mov eax, 0x200
sub edx, 0x1
cmp edx, 0x0
jne next_table
mov eax, cr4 ;enable PAE-paging
or eax, 1 << 5
mov cr4, eax
mov ecx, 0xC0000080 ;set long mode bit in EFER MSR
rdmsr
or eax, 1 << 8
wrmsr
mov eax, cr0 ;enable paging
or eax, 1 << 31
mov cr0, eax
lgdt[gdtr] ;load a 64 bit gdt (will be ignored afterwards)
jmp 0x08:longMode
bits 64
longMode:
mov ax, 0x10 ;10000b = 10 for segment selector 2 (data)
mov ss, ax
mov rsp, 0x80000
mov rdi, 0x30000 ;address where elf reading occurs
mov rsi, 0x30000
add rdi, 24 ;program entry
mov rax, [rdi] ;placed in rax
add rdi, 8 ;program header table position
mov rbx, [rdi] ;put it in rbx
add rdi, 24 ;move to number of entries in program header
mov cx, [rdi] ;put it in cx (2 bytes)
mov rdi, 0x30000 ;beginning of file
add rdi, rbx ;go to program header 0
add rsi, rbx
next_segment:
mov edx, [rdi] ;put the type of segment in edx (4 bytes)
cmp edx, 0x1 ;determine if it is loadable
jne not_loadable ;if it isnt jump to not_loadable
add rdi, 0x8 ;else load it
mov r8, [rdi] ;put the offset in the file where data for this segment resides in r8
add rdi, 0x8 ;go to virtual address of segment
mov r9, [rdi] ;put it in r9
add rdi, 0x10 ;move to size of segment in file
mov r10, [rdi] ;put it in r10
add rdi, 0x8 ;move to size of segment in memory
mov r11, [rdi] ;put it in r11
mov rdi, 0x30000 ;move back to beginning of file
add rdi, r8 ;add segment offset to be at the segment position
next_byte:
mov dl, [rdi] ;put the byte at rdi in dl
mov [r9], dl ;move it to virtual address in r9
add r9, 0x1 ;add 1 byte to virtual address
add rdi, 0x1 ;add 1 byte to rdi
sub r10, 0x1 ;substract 1 byte from size of segment in file
sub r11, 0x1 ;substract 1 byte from size of segment in memory
cmp r10, 0x0 ;is segment finished
jne next_byte ;if not go to next_byte
cmp r11, 0x0 ;if yes tcheck memory size
je no_padding ;if no padding required jmp to no_padding
padding:
xor dl, dl
mov [r9], dl
add r9, 0x01
sub r11, 0x1
cmp r11, 0x0
jne padding
not_loadable:
no_padding:
sub cx, 0x1
cmp cx, 0x0
je finished
add rsi, 56
mov rdi, rsi
jmp next_segment
finished:
jmp rax ;Jump to the entry point of the ELF CPP file
halt:
hlt
jmp halt
;The 64-bits GDT
gdt_start:
dw 0xFFFF
dw 0
db 0
db 0
db 1
db 0
gdt_code:
dw 0x1111 ;limit 0-15
dw 0x0 ;base 0-15
db 0x0 ;base 16-23
db 10011010b ;pr, privi (2), s, ex, dc, rw, ac
db 10101111b ;gr, sz, limit 16-19
db 0x0 ;base 24-31
gdt_data:
dw 0x1111
dw 0x0
db 0x0
db 10010010b
db 00001111b
db 0x0
gdtr:
dw $ - gdt_start - 1
dq gdt_start
Now open a bash terminal and type the following commands in order (making sure to have NASM, g++ and QEMU installed):
nasm -fbin OS/boot.asm -oOS/boot.bin
nasm -fbin OS/paging.asm -oOS/paging.bin
g++ -static -ffreestanding -nostdlib -c -m64 OS/kernel.cpp -oOS/kernel.o
ld --entry main --oformat elf64-x86-64 --no-dynamic-linker -static -nostdlib OS/kernel.o -oOS/kernel.elf
dd if=/dev/zero of=OS/disk.img count=100 & dd if=OS/boot.bin of=OS/disk.img conv=notrunc & dd if=OS/paging.bin of=OS/disk.img seek=1 conv=notrunc & dd if=OS/kernel.elf of=OS/disk.img seek=9 conv=notrunc
qemu-system-x86_64 -hda OS/disk.img -s
You can always put all that in a bash file and launch it automatically. The -s in the QEMU command makes the virtual machine listen on port 1234. You can use gdb to debug the kernel. Type in gdb in a bash shell then target remote localhost:1234. You will then be debugging the machine. You can type dump memory result.bin 0x1000 0x2000 to dump the memory of the machine from 0x1000 to 0x2000 (or any address) in the file result.bin. You can use hexdump -C result.bin to look at the memory dump from terminal. The output is little endian so you need to reverse it for the actual values.
In the code above I'm loading the ELF file compiled with g++ to address 0x30000. Then I'm parsing the file and jumping to its entry point. The cpp code maps the framebuffer in virtual memory and makes a few pixels become white. The code is far from perfect but if you understand it in its entirety then you can go a long way.
I set the following breakpoint:
bp MSPTLS!LsCreateLine 100
The program crashes before the break point is hit 100 times. When I do bl after the crash, I get the following:
0 e 5dca4b62 0072 (0100) 0:**** MSPTLS!LsCreateLine
I am assuming from this information that the break point was hit 72 times before the crash.
However, when I do bp MSPTLS!LsCreateLine 80 I am able to hit the breakpoint before the crash telling me that the break point was hit more than 72 times before the crash. Does this 72 not indicate how many times the break point was hit?
The default number format of WinDbg is hexadecimal. If you want decimal numbers, prefix them with 0n:
0:005> bp ntdll!DbgBreakPoint 0n100
0:005> bl
0 e 7735000c 0064 (0064) 0:**** ntdll!DbgBreakPoint
The counter 0064 before (0064) counts backwards. You can easily observe that in any GUI application:
0:000> bl
0 e 74fd78d7 000a (000a) 0:**** USER32!NtUserGetMessage+0x15
1 e 74fd78c2 0064 (0064) 0:**** USER32!NtUserGetMessage
0:000> g
Breakpoint 0 hit
eax=00000001 ebx=00000001 ecx=00000000 edx=00000000 esi=001faf8c edi=74fd787b
eip=74fd78d7 esp=001faf44 ebp=001faf60 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
USER32!NtUserGetMessage+0x15:
74fd78d7 83c404 add esp,4
0:000> bl
0 e 74fd78d7 0001 (000a) 0:**** USER32!NtUserGetMessage+0x15
1 e 74fd78c2 005a (0064) 0:**** USER32!NtUserGetMessage
0:000> ? 5a
Evaluate expression: 90 = 0000005a
In the example, breakpoint 0 has been hit 10 times, leaving breakpoint 1 at 90.