I'm trying to add new (dummy) system call to linux kernel.
1) I added the system call code under linux-source/kernel/myfile.c and updated the Makefile accordingly.
2) Updated syscall.h, unistd.h and entry.S files to reflect the new system call (pedagogictime(int flag,struct timeval *time))
Then compiled the kernel and installed and rebooted the image.
When I run: cat /proc/kallsyms | grep "pedag", this is the output I'm getting
0000000000000000 T sys_pedagogictime
0000000000000000 d event_exit__pedagogictime
0000000000000000 d event_enter__pedagogictime
0000000000000000 d __syscall_meta_pedagogictime
0000000000000000 d types_pedagogictime
0000000000000000 d args__pedagogictime
0000000000000000 t trace_init_flags_enter__pedagogictime
0000000000000000 t trace_init_flags_exit__pedagogictime
0000000000000000 t __event_exit__pedagogictime
0000000000000000 t __event_enter__pedagogictime
0000000000000000 t __p_syscall_meta__pedagogictime
0000000000000000 t __initcall_trace_init_flags_exit__pedagogictimeearly
0000000000000000 t __initcall_trace_init_flags_enter__pedagogictimeearly
which means the system call is registered correctly.
In my user space program, I'm writing:
#define __NR_pedagogictime 1326 //1326 is my system call number
struct timeval *now = (struct timeval *)malloc(sizeof(struct timeval));
long ret = syscall(__NR_pedagogictime,0,now);
if(ret)
perror("syscall ");
But I'm getting the error:
"syscall : Function not implemented"
I would really appreciate any help about this. Thanks.
Edit:
Btw, the assembly code for the syscall() looks like this (if it helps):
movl $6, %esi
movl $1326, %edi
movl $0, %eax
call syscall
cltq
You've chosen the wrong syscall number. Take a look at how the kernel checks the syscall number limits here. For example (x86, 32bit):
496 ENTRY(system_call)
497 RING0_INT_FRAME # can't unwind into user space anyway
498 pushl_cfi %eax # save orig_eax
499 SAVE_ALL
500 GET_THREAD_INFO(%ebp)
501 # system call tracing in operation / emulation
502 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
503 jnz syscall_trace_entry
504 cmpl $(nr_syscalls), %eax
505 jae syscall_badsys
506 syscall_call:
507 call *sys_call_table(,%eax,4)
508 movl %eax,PT_EAX(%esp) # store the return value
So, you can see that this code compares %eax (syscall number) and nr_syscalls (sys_call_table size). Above or equal leads to syscall_badsys.
You'll need to modify the arch/x86/include/asm/unistd_32.h header too.
Related
How can i access the exception chain (SEH) using masm64?
Using masm32, I get the first exception looking into fs:[0]
But when I checked in Windbg if fs:[0] still pointed at the first exception in x64, I figured that it wasn't.
I'd like to set an exception in x64 the same way I did in x86. Is it feasible (maybe looking at gs register)?
If this is coding related then you use
ml64seh PROC FRAME:ExceptionFilter
this adds your exception handler to .PDATA section RUNTIME_FUNCTION
if this is how to find this exception handler in windbg when the exception has been raised
use !exchain command
or if you want to find it before executing a specific function use .fnent command
a sample for x64 seh and finding it in windbg is as follows
;assemble and link with
;ml64 /Zi ml64seh.asm /link /debug /entry:ml64seh /subsystem:console
.data
safeplace DWORD ?
.code
ExceptionFilter PROC
jmp Handler
ExceptionFilter ENDP
PUBLIC ml64seh
ml64seh PROC FRAME:ExceptionFilter
.ENDPROLOG
mov rax, 0
mov [rax], rax ;access violation
jmp exit
Handler::
lea rax, safeplace
mov [r8+078h], rax ; replacing rax in exception handler so access is possible
mov rax, 0
ret
Exit:
ret
ml64seh ENDP
END
run without stopping in windbg
:\>cdb -g ml64seh.exe
(2aa0.3024): Access violation - code c0000005 (first chance)
ml64seh!ml64seh+0x7:
00007ff7`0e3b1029 488900 mov qword ptr [rax],rax ds:00000000`00000000=????????????????
0:000>
it crashed and broke now locating exception handlers
0:000> .fnent .
Debugger function entry 0000020b`e36c47a8 for:
(00007ff7`0e3b1022) ml64seh!ml64seh+0x7 | (00007ff7`0e3b32b0) ml64seh!$xdatasym
BeginAddress = 00000000`00001022
EndAddress = 00000000`00001042
UnwindInfoAddress = 00000000`000032b0
Unwind info at 00007ff7`0e3b32b0, c bytes
version 1, flags 3, prolog 0, codes 0
handler routine: ml64seh!ILT+0(ExceptionFilter) (00007ff7`0e3b1005), data 0 <<<<<<<<<
0:000> !exchain
3 stack frames, scanning for handlers...
Frame 0x00: ml64seh!ml64seh+0x7 (00007ff7`0e3b1029)
ehandler ml64seh!ILT+0(ExceptionFilter) (00007ff7`0e3b1005) <<<<<<<<<<<<
Frame 0x02: ntdll!RtlUserThreadStart+0x21 (00007ffe`213c26a1)
ehandler ntdll!_C_specific_handler (00007ffe`213fc720)
0:000>
lets see if we go to the handler and return back to re access the faulting place
0:000> bp .
0:000> bp 00007ff7`0e3b1005
0:000> bl
0 e 00007ff7`0e3b1029 0001 (0001) 0:**** ml64seh!ml64seh+0x7
1 e 00007ff7`0e3b1005 0001 (0001) 0:**** ml64seh!ILT+0(ExceptionFilter)
0:000> g
Breakpoint 1 hit
ml64seh!ILT+0(ExceptionFilter):
00007ff7`0e3b1005 e916000000 jmp ml64seh!ExceptionFilter (00007ff7`0e3b1020)
0:000> g
Breakpoint 0 hit
ml64seh!ml64seh+0x7: is accessible now
00007ff7`0e3b1029 488900 mov qword ptr [rax],rax ds:00007ff7`0e3b4000=0000000000000000
0:000>
btw you can use dumpbin or linker to spit out all the unwindinfos in a specific binary using -unwindinfo switch
:\>dumpbin /unwindinfo ml64seh.exe
Microsoft (R) COFF/PE Dumper Version 14.29.30146.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file ml64seh.exe
File Type: EXECUTABLE IMAGE
Function Table (1)
Begin End Info Function Name
00000000 00001022 00001042 000032B0 ml64seh
Unwind version: 1
Unwind flags: EHANDLER UHANDLER
Size of prologue: 0x00
Count of codes: 0
Handler: 00001005 #ILT+0(ExceptionFilter)
I'm writing a small Kernel to learn more about Operating ystems.
I recently decided to start implementing User Mode, just for fun.
To achieve this, I followed this guide: https://blog.llandsmeer.com/tech/2019/07/21/uefi-x64-userland.html
Unfortunately, though, I've seen nothing but gpfaults, page faults and reboots in the last 24 hours. I tried and retried, following many different guides, from the OSDev Wiki, to random blogs, and checking with Volume 2 of the AMD Programmer's Manual for x86-64, but nothing. It seems as though, instead of jumping to user_main, sysretq rejumps to kernel_main (Indeed, running the function twice results in the same weird page fault - with a random text output that should only be displaied once [at boot]). If i use sysret or o64 sysret instead of sysretq, QEMU outright resets.
I seriously don't know how to deal with this problem.
Links and references:
You can find my Kernel at: https://github.com/Alessandro-Salerno/SalernOS-Kernel
The code for entering User Mode can be found at src/User/Userspace/userspace.asm and the SCE (System Call Extension) code can be found at src/Syscall/sce.asm. The entry point is in src/kernel.c
The code I use in kernel.c to jump to Userspace.
...
#include "User/Userspace/userspace.h"
uint64_t user_stack[1024];
void user_main() {
while (TRUE);
}
void kernel_main(boot_t* __bootinfo) {
// init code (Up to line 74 in src/kernel.c)
kernel_userspace_enter(user_main, &user_stack[500]);
}
Nth Edit: I used log cpu_reset in QEMU to get some info when the system crashes:
CPU Reset (CPU 0)
RAX=0000000000006297 RBX=000000000ff1c2b0 RCX=0000000000002d60 RDX=00000000ff000000
RSI=0000000000009ff8 RDI=0000000000002d60 RBP=0000000000000000 RSP=0000000000009ff8
R8 =0000000000000000 R9 =000000000000a1f0 R10=cccccccccccccccd R11=0000000000000202
R12=000000000ff1c176 R13=000000000ff1c177 R14=0000000000006296 R15=0000000000000000
RIP=0000000000002d60 RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000fff 00a09300 DPL=0 DS [-WA]
CS =002b 0000000000000000 ffffffff 00a0fb00 DPL=3 CS64 [-RA]
SS =0023 0000000000000000 ffffffff 00c0f300 DPL=3 DS [-WA]
DS =0010 0000000000000000 00000fff 00a09300 DPL=0 DS [-WA]
FS =0010 0000000000000000 00000fff 00a09300 DPL=0 DS [-WA]
GS =0010 0000000000000000 00000fff 00a09300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0030 000000000000a000 00068fff 00a08900 DPL=0 TSS64-avl
GDT= 0000000000005000 00000fff
IDT= 000000000021f000 00000fff
CR0=80010033 CR2=fffffffffffffff8 CR3=0000000000100000 CR4=00000668
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000000 CCD=000000000ff1c150 CCO=EFLAGS
EFER=0000000000000d01
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=ff000000ff000000 ff000000ff000000 XMM01=0000000000000000 3ff0000000000000
XMM02=0000000000000000 0000000000000000 XMM03=0015001600400003 0038004000000000
XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000
XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
XMM08=0000000000000000 0000000000000000 XMM09=0000000000000000 0000000000000000
XMM10=0000000000000000 0000000000000000 XMM11=0000000000000000 0000000000000000
XMM12=0000000000000000 0000000000000000 XMM13=0000000000000000 0000000000000000
XMM14=0000000000000000 0000000000000000 XMM15=0000000000000000 0000000000000000
I solved it.
At letast I think so....
Remember to get the size of the GDT instance, not the GDT Type when setting up your GDT. If I find something else, I will update this answer.
I am trying socket programming for ARM, however I am not able to understand how the values for the arguments are decided.
For example
this is the link for Azeria Labs
I understand that sys call for ARM register R7 gets it hence its 281 in this case and arguments are passed using R0, R1, R2, R3. But here how do you decide the values for R0(AF_INET) as 2 and R1(SOCK_STREAM) as 1 while creating socket(AF_INET, SOCK_STREAM, 0)
Finding system call was easy
$ grep socket /usr/include/asm/unistd-common.h
#define __NR_socket (__NR_SYSCALL_BASE+281)
#define __NR_socketpair (__NR_SYSCALL_BASE+288)
Similarly is there a way to find the values for the arguments?
I found an another resource which was for X86 Assembly which also has similar approach.
%assign SOCK_STREAM 1
%assign AF_INET 2
%assign SYS_socketcall 102
%assign SYS_SOCKET 1
%assign SYS_CONNECT 3
%assign SYS_SEND 9
%assign SYS_RECV 10
section .text
global _start
;--------------------------------------------------
;Functions to make things easier. :]
;--------------------------------------------------
_socket:
mov [cArray+0], dword AF_INET
mov [cArray+4], dword SOCK_STREAM
mov [cArray+8], dword 0
mov eax, SYS_socketcall
mov ebx, SYS_SOCKET
mov ecx, cArray
int 0x80
ret
Kindly let me know.
Thank you.
Linux alarmpi 4.4.34+ #3 Thu Dec 1 14:44:23 IST 2016 armv6l GNU/Linux
%include "init.inc"
[org 0x0]
[bits 16]
jmp 0x07C0:start_boot
start_boot:
mov ax, cs
mov ds, ax
mov es, ax
load_setup:
mov ax, SETUP_SEG
mov es, ax
xor bx, bx
mov ah, 2 ; copy data to es:bx from disk.
mov al, 1 ; read a sector.
mov ch, 0 ; cylinder 0
mov cl, 2 ; read data since sector 2.
mov dh, 0 ; Head = 0
mov dl, 0 ; Drive = 0
int 0x13 ; BIOS call.
jc load_setup
lea si, [msg_load_setup]
call print
jmp $
print:
print_beg:
mov ax, 0xB800
mov es, ax
xor di, di
print_msg:
mov al, byte [si]
mov byte [es:di], al
or al, al
jz print_end
inc di
mov byte [es:di], BG_TEXT_COLOR
inc di
inc si
jmp print_msg
print_end:
ret
msg_load_setup db "Loading setup.bin was completed." , 0
times 510-($-$$) db 0
dw 0xAA55
I want to load setup.bin to memory address zero. So, I input 0 value to es register (SETUP_SEG = 0). bx, too. But it didn't work. then, I have a question about this issue. My test is below.
SETUP_SEG's value
0x0000 : fail
0x0010 : success
0x0020 : fail
0x0030 : fail
0x0040 : fail
0x0050 : success
I can't understand why this situation was happened. All test was carried out on VMware. Does anyone have an idea ?
I'm not sure if this is your problem, but your trying to load setup.bin in the Real Mode IVT (Interrupt Vector Table). The IVT contains the location of each interrupt, so I'm assuming that your boatloader is overwriting them when it loads setup.bin into memory! Interrupts can be sneaky and tricky, since they can be called even if you didn't call them. Any interrupt vector you overwrote will likely cause undefined behavior when called, which will cause some problems.
I suggest setting SETUP_SEG to a higher number like 0x2000 or 0x3000, but the lowest you could safely go is 0x07E0. The Osdev Wiki and Wikipedia have some helpful information on conventional memory and memory mapping.
I hope this helps!
I'm trying to learn Y86, so I made a very simple program. It has an array of three long integers, and each block is filled by asking the user for an input through rdint.
The compiled(?) program asks for three inputs, but is not able to print them out.
Code:
Main: irmovl Array, %edx
rdint %eax
rmmovl %eax, 0(%edx)
rdint %eax
rmmovl %eax, 4(%edx)
rdint %eax
rmmovl %eax, 8(%edx)
irmovl $10, %edi
Print: irmovl Array, %edx
mrmovl 0(%edx), %eax
wrch %eax
wrch %edi
mrmovl 4(%edx), %eax
wrch %eax
wrch %edi
mrmovl 8(%edx), %eax
wrch %eax
wrch %edi
halt
.align 4
Array:
.long 0
.long 0
.long 0
My input:
0
1
2
Output:
(three blank lines below)
Stopped in 22 steps at PC = 0x47. Exception 'HLT', CC Z=1 S=0 O=0
Changes to registers:
%edx: 0x00000000 0x0000004c
%edi: 0x00000000 0x0000000a
Changes to memory:
0x0004: 0x024008f2 0x00000001
0x0008: 0x00000000 0x00000002
Changes to memory: 0x0004: 0x024008f2 0x00000001 0x0008:
0x00000000 0x00000002
There is a classic problem with the program: Lack of new-line in the ys file, causing YAS to misbehave.
The first problem is due to an error in YAS. If you look in the yo file produced by YAS you will see that the last .long 0 statement never gets defined. You will probably also see that the first line opcode in the yo file is 0x00, i.e. nop (when YAS encounter a final instruction without an associated newline, it wraps it around, screwing up the yo file)
This means that you loose the first irmovl Array, %edx (it becomes some sort of nonsense, probably 0x00000000, i.e. 4 nops,) and so you write the first read character x'30' (ascii for '0') to the location pointd to by edx (which is probably 0x00000000,) is in the first instruction (which was 4 nops -- remember that you read a character, but it ends up in a 4 byte register and is saved as such.) So you are writing 0x00000000 to and address that was 0x00000000, which to YIS means that the register was not changed and therefore it is not shown in the "Changes to Memory" dump section.
You repeat this with the second read, writing 0x00000001 in the second word (overwriting the instruction in that location,) and with the third read, writing 0x00000002 in the third word (overwriting the instruction in that location.)
Now, of course, you are completely hosed! You reset the pointer to the array (using edx,) and attempt to print the content, but Array(0), Array(4), and Array(8) contains 0x00000000, because that is what you defined it as (using your .long 4 statements for Array(0) and Array(4) and automatically for Array(8) since the default set-up for undefined memory in Y86 is 0x00000000. And so, the program prints x'00' (because you print one character from a 4 byte word,) which, of course, is junk.
You will note that this fits with the dump from YIS. eax does not show as it is unchanged from 0x00000000, its initial value. edx and edi look A-OK, with edi pointing to Array(8). The only memory that has changed is the second and third word of the program (which have been overwritten with 0x00000001 and 0x00000002, respectively)
So, in summary. YAS makes a mistake. You must overcome this problem by adding a new-line after the last .long 0 statement. YIS misleads you because, critically!, it does not throw exceptions when you overwrite code with data.