Page 1 of 1

[Solved] Finding offset to write to read() buffer

Posted: Thu Mar 09, 2017 12:18 am
by codyd51
Hi!

I've ported newlib to my OS, but am having some issues with read() and getchar(). If I call read() with a buffer on the stack, everything works as expected and I can write to the buffer from the kernel without needing to modify the address at all.

However, if I attempt to call getchar() through newlib, then I see a read() syscall being made with something like the following parameters: read(0, 0x10, 1024). So, read is asking to write to a buffer really low in memory. Am I supposed to be doing something to this address before writing to it? Is this address supposed to be an offset into .bss, or some other segment? If it is an offset into a segment, how am I to differentiate between when the kernel is being given a buffer on the stack (which requires no translation) vs. an offset into a segment (which does require translation)?

Just to demonstrate, here's a screenshot of output when using newlib's getchar() in a loaded ELF. You'll also notice some garbage characters being printed, which is strange considering the ELF loader zeroes-out the .bss segment, and sbrk does the same to any memory it gives it. That's another thing I'm still trying to figure out. http://imgur.com/gallery/wmUKS

Any tips or ideas are appreciated, thanks!

Re: Finding offset to write to read() buffer

Posted: Thu Mar 09, 2017 12:51 am
by Velko
Am I supposed to be doing something to this address before writing to it?
No. You just fill memory at this address, no translation of any kind. You should, however, validate
if it points to sane location (and refuse to proceed in this particular case).

Newlib allocates buffer(s) in heap for stdio routines. Check if your sbrk() and malloc() works as expected.

Re: Finding offset to write to read() buffer

Posted: Thu Mar 09, 2017 11:37 am
by codyd51
Velko wrote:
Am I supposed to be doing something to this address before writing to it?
No. You just fill memory at this address, no translation of any kind. You should, however, validate
if it points to sane location (and refuse to proceed in this particular case).

Newlib allocates buffer(s) in heap for stdio routines. Check if your sbrk() and malloc() works as expected.
Gotcha, thanks for clearing that up! I tried a malloc() with newlib, and, as expected, got a very low address in memory (0x10). Trying getchar() again gives read() a buffer around 0x410. What I don't understand is why these addresses are so low, when sbrk() gives addresses above 0x8050000. Also, when I attempt to write to this buffer without translation, I still get garbled memory on the ELF-side.

Re: Finding offset to write to read() buffer

Posted: Thu Mar 09, 2017 11:40 am
by codyd51
Ah, I just logged sbrk on the elf-side and realized that it's not returning the correct values to the program. I think my syscall handler might be trashing eax after running the syscall function. I'll fix my syscalls to make sure they're returning values as expected and try again. Thanks for your help!

Re: Finding offset to write to read() buffer

Posted: Thu Mar 09, 2017 1:15 pm
by codyd51
Okay, syscalls are now returning values properly. If I read() into a buffer myself and print it out, everything works as expected, However, if I attempt to use getchar(), EOF is returned. Why would this be?

Re: Finding offset to write to read() buffer

Posted: Thu Mar 09, 2017 3:18 pm
by lkurusa
Hi,

Is your read system call working properly as expected? In newlib, can you trace what your kernel passes? Maybe it gets zero'd somewhere?

Lastly, do you get EOF as well when you are issuing a read system call?

Re: Finding offset to write to read() buffer

Posted: Thu Mar 09, 2017 9:15 pm
by codyd51
lev wrote:Hi,

Is your read system call working properly as expected? In newlib, can you trace what your kernel passes? Maybe it gets zero'd somewhere?

Lastly, do you get EOF as well when you are issuing a read system call?

As a matter of fact, yes. If I call read() manually from an ELF, everything works fine. It's only when I try to use newlib's getchar. It seems newlib's sprintf is also borked, which may or may not be a related issue.

No. My current read implementation, for testing purposes, never gives EOF.

Re: Finding offset to write to read() buffer

Posted: Fri Mar 10, 2017 12:55 am
by Velko
Return value of read() syscall?

Re: Finding offset to write to read() buffer

Posted: Fri Mar 10, 2017 3:49 am
by Solar
Do your OS and newlib agree on what stdin is? This looks like newlib taking its buffer address from some uninitialized structure...?!?

(No idea about newlib's internals, I am just guessing here.)

Re: Finding offset to write to read() buffer

Posted: Fri Mar 10, 2017 11:04 pm
by codyd51
Velko wrote:Return value of read() syscall?
Thank you!! This was the issue. I appreciate you pointing me in the right direction!

The exact problem was this syscall stub in newlib:

Code: Select all

int read(int fd, char* buf, int count) {
    sys_read(fd, buf, count);
    return 0;
}
For some stupid reason I wasn't returning sys_read's return value. So, the buffer was filled correctly, which is why when calling read() myself the buffer was filled as expected, but the caller is told that no characters were read, which is why getchar() returned EOF.

Thanks for the help, everyone!