Can't load flat binary file into kernel - operating-system

NOTE - I don't have paging set up yet and my kernel is multi-boot, ELF. I do have irqs and the isrs done.
So I have this GAS file here:
.section .text
.global _start
_start:
mov $0xDEADBEEF, %eax
And GRUB2 setup to load the flat binary file:
menuentry "fOS-Terminal (25x80)" {
multiboot /boot/fos.elf
module /modules/program.bin
set gfxmode=80x25
}
And here in my kernel.c, I can parse the multiboot header to get the module's address and I am calling it:
typedef void (*call_module_t)(void);
call_module_t start_program = (call_module_t)mbd->mods_addr;
start_program();
Right now I am trying to compile my GAS file into a flat binary with these commands:
i686-elf-as --32 ./iso/modules/program.s -o ./iso/modules/program.o
i686-elf-ld -fPIC -shared --oformat binary ./iso/modules/program.o -o ./iso/modules/program.bin
PROBLEM - GRUB2 is surely loading the kernel, multi-boot header is telling me it's at address - 0x100ac but when I go there, I get the exception: INVALID OPCODE.
This seems helpful but is not :(
https://littleosbook.github.io/book.pdf#page=49&zoom=auto,-100,472
EDIT - 1 So when I gdb'd to the calling function, this comes up:

Here is the problem
typedef void (*call_module_t)(void);
call_module_t start_program = (call_module_t)mbd->mods_addr;
start_program();
mbd->mods_addr is the address of modules structure table. And not the address to module itself.
so what is the solution?
unsigned int* modules = (unsigned int*)mbd->mods_addr;
if (mbd->mods_count > 0)
{
unsigned int addr = modules[0];
unsigned int size = modules[1];
call_module_t start_program = (call_module_t)addr;
start_program();
}
else
painc("module wasn't loaded");

Related

BPF Ring Buffer Invalid Argument (-22)?

I wanted to use eBPF's latest map, BPF_MAP_TYPE_RINGBUF, but I can't find much information online on how I can use it, so I am just doing some trial-and-error here. I defined and used it like this:
struct bpf_map_def SEC("maps") r_buf = {
.type = BPF_MAP_TYPE_RINGBUF,
.max_entries = 1 << 2,
};
SEC("lsm/task_alloc")
int BPF_PROG(task_alloc, struct task_struct *task, unsigned long clone_flags) {
uint32_t pid = task->pid;
bpf_ringbuf_output(&r_buf, &pid, sizeof(uint32_t), 0); //stores the pid value to the ring buffer
return 0;
}
But I got the following error when running:
libbpf: map 'r_buf': failed to create: Invalid argument(-22)
libbpf: failed to load object 'bpf_example_kern'
libbpf: failed to load BPF skeleton 'bpf_example_kern': -22
It seems like libbpf does not recognize BPF_MAP_TYPE_RINGBUF? I cloned the latest libbpf from GitHub and did make and make install. I am using Linux 5.8.0 kernel.
UPDATE: The issue seems to be resolved if I changed the max_entries to something like 4096 * 64, but I don't know why this is the case.
You are right, the problem is in the size of BPF_MAP_TYPE_RINGBUF (max_entries attribute in libbpf map definition). It has to be a multiple of a memory page (which is 4096 bytes at least on most popular platforms). So that explains why it all worked when you specified 64 * 4096.
BTW, if you'd like to see some examples of using it, I'd start with BPF selftests:
user-space part: https://github.com/torvalds/linux/blob/master/tools/testing/selftests/bpf/prog_tests/ringbuf.c
kernel (BPF) part: https://github.com/torvalds/linux/blob/master/tools/testing/selftests/bpf/progs/test_ringbuf.c

Asan don't report leak info

I write a simple c++ program that use new function and don't use delete function, then I use asan, but it not report.
#include <iostream>
#include <stdint.h>
using namespace std;
int main()
{
int *p = new int[50];
for (uint32_t i = 0; i < 50; ++i)
{
*(p + i ) = i;
}
cout << *p << endl;
return 0;
}
then ./g++ main.cpp -lasan -L/root/local/lib64/ -fsanitize=address -fno-omit-frame-pointer -g
and print 0, but not report delete leak . why ?
if I use export LD_PRELOAD=/usr/local/lib64/libasan.so.0.0.0, then ./g++ main.cpp
report
g++: internal compiler error: Segmentation fault (program collect2)
0x40c400 execute
../../gcc/gcc.c:2823
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.
it look like collect2 core dump ,so I run cd libexec/gcc/x86_64-unknown-linux-gnu/4.8.5/ && ./colloct2, report Segmentation fault (core dumped)
I use source to install gcc-4.8.5, centos 6.
gcc-4_8-branch doesn't even contain libsanitizer/lsan/ directory. Please try more recent GCC versions. by https://github.com/google/sanitizers/issues/699

Page fault with newlib functions

I've been porting newlib to my very small kernel, and I'm stumped: whenever I include a function that references a system call, my program will page fault on execution. If I call a function that does not reference a system call, like rand(), nothing will go wrong.
Note: By include, I mean as long as the function, e.g. printf() or fopen(), is somewhere inside the program, even if it isn't called through main().
I've had this problem for quite some time now, and have no idea what could be causing this:
I've rebuilt newlib numerous times
Modified my ELF loader to load the
code from the section headers instead of program headers
Attempted to build newlib/libgloss separately (which failed)
Linked the libraries (libc, libnosys) through the ld script using GROUP, gcc and ld
I'm not quite sure what other information I should include with this, but I'd be happy to include what I can.
Edit: To verify, the page faults occurring are not at the addresses of the failing functions; they are elsewhere in the program. For example, when I call fopen(), located at 0x08048170, I will page fault at 0xA00A316C.
Edit 2:
Relevant code for loading ELF:
int krun(u8int *name) {
int fd = kopen(name);
Elf32_Ehdr *ehdr = kmalloc(sizeof(Elf32_Ehdr*));
read(fd, ehdr, sizeof(Elf32_Ehdr));
if (ehdr->e_ident[0] != 0x7F || ehdr->e_ident[1] != 'E' || ehdr->e_ident[2] != 'L' || ehdr->e_ident[3] != 'F') {
kfree(ehdr);
return -1;
}
int pheaders = ehdr->e_phnum;
int phoff = ehdr->e_phoff;
int phsize = ehdr->e_phentsize;
int sheaders = ehdr->e_shnum;
int shoff = ehdr->e_shoff;
int shsize = ehdr->e_shentsize;
for (int i = 0; i < pheaders; i++) {
lseek(fd, phoff + phsize * i, SEEK_SET);
Elf32_Phdr *phdr = kmalloc(sizeof(Elf32_Phdr*));
read(fd, phdr, sizeof(Elf32_Phdr));
u32int page = PMMAllocPage();
int flags = 0;
if (phdr->p_flags & PF_R) flags |= PAGE_PRESENT;
if (phdr->p_flags & PF_W) flags |= PAGE_WRITE;
int pages = (phdr->p_memsz / 0x1000) + 1;
while (pages >= 0) {
u32int mapaddr = (phdr->p_vaddr + (pages * 0x1000)) & 0xFFFFF000;
map(mapaddr, page, flags | PAGE_USER);
pages--;
}
lseek(fd, phdr->p_offset, SEEK_SET);
read(fd, (void *)phdr->p_vaddr, phdr->p_filesz);
kfree(phdr);
}
// Removed: code block that zeroes .bss: it's already zeroed whenever I check it anyways
// Removed: code block that creates thread and adds it to scheduler
kfree(ehdr);
return 0;
}
Edit 3: I've noticed that if I call a system call, such as write(), and then call printf() two or more times, I will get an unknown opcode interrupt. Odd.
Whoops! Figured it out: when I map the virtual address, I should allocate a new page each time, like so:
map(mapaddr, PMMAllocPage(), flags | PAGE_USER);
Now it works fine.
For those curious as to why it didn't work: when I wasn't including printf(), the size of the program was under 0x1000 bytes, so mapping with only one page was okay. When I include printf() or fopen(), the size of the program was much bigger so that's what caused the issue.

Executable encryption check anti piracy measure

I read a very interesting blog about implementing some anti-piracy protection into your apps. Some of them dont work anymore, some of them do. The 2 ones that still are effective to an extent are the 2 last ones listed.
http://shmoopi.wordpress.com/2011/06/19/27/
The one I'm interested in is the very last one. Code below. I've implemented this in my AppDelegate.m
Anti piracy via the encryption check.
Required Headers
#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <TargetConditionals.h>
Encryption Struct
#if TARGET_IPHONE_SIMULATOR && !defined(LC_ENCRYPTION_INFO)
#define LC_ENCRYPTION_INFO 0x21
struct encryption_info_command
{
uint32_t cmd;
uint32_t cmdsize;
uint32_t cryptoff;
uint32_t cryptsize;
uint32_t cryptid;
};
#endif
Needed Methods
int main (int argc, char *argv[]);
static BOOL is_encrypted ()
{
const struct mach_header *header;
Dl_info dlinfo;
/* Fetch the dlinfo for main() */
if (dladdr(main, &dlinfo) == 0 || dlinfo.dli_fbase == NULL)
{
NSLog(#"Could not find main() symbol (very odd)");
return NO;
}
header = dlinfo.dli_fbase;
/* Compute the image size and search for a UUID */
struct load_command *cmd = (struct load_command *) (header+1);
for (uint32_t i = 0; cmd != NULL && i < header->ncmds; i++)
{
/* Encryption info segment */
if (cmd->cmd == LC_ENCRYPTION_INFO)
{
struct encryption_info_command *crypt_cmd = (struct encryption_info_command *) cmd;
/* Check if binary encryption is enabled */
if (crypt_cmd->cryptid < 1)
{
return NO;
}
return YES;
}
cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize);
}
return NO;
}
This method checks to see if the binary is still encrypted.
When I run this on the device attached to x-code it gives me a false positive on this line
if (crypt_cmd->cryptid < 1)
{
NSLog(#"Pirated from (crypt_cmd->cryptid < 1) ");
return NO;
}
I was wondering is it possible that the builds xcode puts onto the device for debugging purposes not encrypted? And its only encrypted when the build is submitted to Apple for use on iTunes. Hence why I am getting this false positive when check the code.
Many Thanks,
-Code
This code won't work successfully on a 64-bit device like the iPhone 5s. The header has been changed from mach_header to mach_header_64 and the command ID is now LC_ENCRYPTION_INFO_64.
What I did was to read the header and then see what the magic number was. If it's MH_MAGIC_64 then you're on a 64-bit device and you need to use the mach_header_64 struct and look for LC_ENCRYPTION_INFO_64 (defined as 0x2C) instead of LC_ENCRYPTION_INFO.
A better otool command to see whether a file is encrypted or not is:
otool -arch armv7 -l YourAppName | grep crypt
I have been looking into this recently as well and tested with the same results. It turns out this code is telling you YES or NO based on whether the binary is encrypted with Apple's FairPlay DRM. Any debug or ad-hoc builds you do will say NO.
You can see the same information on your binary or any iPhone apps you have purchased using the otool command-line tool.
For your own binaries, find the binary in your project under e.g. build/Debug-iphoneos/MyApp.app and run (from Terminal)
otool -l MyApp | more
Scan through for cryptid in the LC_ENCRYPTION_INFO section. Since this is a debug build it will be 0. If you have synched your phone to your computer, check under ~/Music/iTunes/Mobile Applications and pick an .ipa file. Unzip it and try otool against the binary from the .ipa and it should have 1 for the cryptid.
It looks like this is looking for the signature block in the dyload header. This means that you're only going to see this on code which is signed. Chances are that your code isn't being automatically signed for debugging (unnecessary), although it will be signed when it goes to the device.
You might want to make this entire check conditional on the project running on an iOS device instead of in the simulator. Any binary sent to an iOS device must be signed.
#if !(TARGET_IPHONE_SIMULATOR)
your check
#endif //

How do I do inline assembly on the IPhone?

How is it done? What steps do I need to take and what pitfalls and gotchas are there to consider?
I've gotten this to work, thanks to some inside help over at the Apple Devforums, you should sign up if you're a dedicated IPhone developer.
First thing's first, it's __asm__(), not plain asm().
Secondly, by default, XCode generates a compilation target that compiles inline assembly against the ARM Thumb instruction set, so usat wasn't recognized as a proper instruction. To fix this, do "Get Info" on the Target. Scroll down to the section "GCC 4.0 - Code Generation" and uncheck "Compile for Thumb". Then this following snippet will compile just fine if you set the Active SDK to "Device"
inline int asm_saturate_to_255 (int a) {
int y;
__asm__("usat %0, #8, %1\n\t" : "=r"(y) : "r"(a));
return y;
}
Naturally, now it won't work with the IPhone Simulator. But TargetConditionals.h has defines you can #ifdef against. Namely TARGET_OS_IPHONE and TARGET_IPHONE_SIMULATOR.
I write quite a bit of ARM Cortex-A8 assembly-code. The CPU on the iPhone is an ARM11 (afaik) so the core instruction set is the same.
What exactly are you looking for? I could give you some examples if you want.
EDIT:
I just found out that on the iPhone you have to use the llvm-gcc compiler. As far as I know it should understand the inline assembler syntax from GCC. If so all the ARM inline assembler tutorials will work on the iPhone as well.
Here is a very minimal inline assembler function (in C). Could you please tell me if it compiles and works on the iphone? If it works I can rant a bit how to do usefull stuff in ARM inline assembler, especially for the ARMv6 architecture and the DSP extensions.
inline int saturate_to_255 (int a)
{
int y;
asm ("usat %0, #8, %1\n\t" : "=r"(y) : "r"(a));
return y;
}
should be equivalent to:
inline int saturate_to_255 (int a)
{
if (a < 0) a =0;
if (a > 255) a = 255;
return a;
}
The registers can also be used explicitly in inline asm
void foo(void) {
#if TARGET_CPU_ARM64
__asm ("sub sp, sp, #0x60");
__asm ("str x29, [sp, #0x50]");
#endif
}
Thumb is recommended for application which do not require heavy float operation. Thumb makes the code size smaller and results also in a faster code execution.
So you should only turn Thumb off for application like 3D games...
Background
Now is 2021 year -> other answer seems is too old?
the most iOS device(iPhone etc.) is ARM 64bit: arm64
Inline assembly on the iPhone
asm keyword
GNU/GCC compiler
standard C (compile flag: -ansi / -std): use __asm__
GNU extensio: use asm
ARM compiler: use __asm
asm syntax
AFAIK, there many asm syntax
asm syntax
AT&T syntax ~= GNU syntax ~= UNIX syntax
Intel syntax
ARM syntax
here only focus on most common used GNU/GCC syntax
GNU/UNIX syntax
Basic Asm
asm("assembly code");
__asm__("assembly code");
Extended Asm
asm asm-qualifiers ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
My Example code
environment
dev
macOS
IDE: XCode
compiler: clang
running
iOS - iPhone
hardware arch: ARM64
inline asm to call svc 0x80 for ARM64 using Extended Asm
inline asm inside ObjC code
// inline asm code inside iOS ObjC code
__attribute__((always_inline)) long svc_0x80_syscall(int syscall_number, const char * pathname, struct stat * stat_info) {
register const char * x0_pathname asm ("x0") = pathname; // first arg
register struct stat * x1_stat_info asm ("x1") = stat_info; // second arg
register int x16_syscall_number asm ("x16") = syscall_number; // special syscall number store to x16
register int x4_ret asm("x4") = -1; // store result
__asm__ volatile(
"svc #0x80\n"
"mov x4, x0\n"
: "=r"(x4_ret)
: "r"(x0_pathname), "r"(x1_stat_info), "r"(x16_syscall_number)
// : "x0", "x1", "x4", "x16"
);
return x4_ret;
}
call inline asm
// normal ObjC code
#import <sys/syscall.h>
...
int openResult = -1;
struct stat stat_info;
const char * filePathStr = [filePath UTF8String];
...
// call inline asm function
openResult = svc_0x80_syscall(SYS_stat64, filePathStr, &stat_info);
Doc
GCC-Inline-Assembly-HOWTO (ibiblio.org)
Extended Asm (Using the GNU Compiler Collection (GCC))
Procedure Call Standard for the Arm® 64-bit Architecture
ARM GCC Inline Assembler Cookbook
ConvertBasicAsmToExtended - GCC Wiki
ios - fork() implementation by using svc call - Stack Overflow
linux - ARM inline asm: exit system call with value read from memory - Stack Overflow