Reputation: 27
I searched in google I found that Linux kernel uses a struct for variables.
#define EMBEDDED_LEVELS 2
struct nameidata {
struct path path;
struct qstr last;
struct path root;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
unsigned seq, m_seq;
int last_type;
unsigned depth;
int total_link_count;
struct saved {
struct path link;
struct delayed_call done;
const char *name;
unsigned seq;
} *stack, internal[EMBEDDED_LEVELS];
struct filename *name;
struct nameidata *saved;
struct inode *link_inode;
unsigned root_seq;
int dfd;
} __randomize_layout;
for example for execve
systeml call (found here https://elixir.bootlin.com/linux/latest/source/fs/exec.c)
this function will pass the filename pointer to another function as a pathName and set the nameidata struct name to this pathName
static int __do_execve_file(int fd, struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags, struct file *file)
my question here is how is it calculating the length of the parameter passed to this function from stack (for example "/bin/sh"
)?
(Editor's note: the const char *pathname
arg to execve(2)
doesn't have to point to stack memory. I think this question is assuming the shellcode use-case where you do construct a path on the user-space stack and pass a pointer to that.)
(I am learning assembly and I'm stuck in parameter passing section to system calls)
Upvotes: 0
Views: 637
Reputation: 27
Finally i found my answer
here is the source code that i found
#include <stdio.h>
char hello[] = "HelloA\0AAABB";
int main( void )
{
__asm__
(
"mov $hello , %eax;"
"push %eax;"
"call myprint;"
);
}
void myprint(char input[])
{
printf("%s" , input);
}
I found that '\0' is the string terminator.so the above code will just output the "HelloA".The rest of it will be ignored.
Another interesting thing that i found is that when you create an array of char in C. the compiler will add a byte at the end of it for the null terminator.
So if we create something like this
char hello[] = "Hello"
It actually compile it like this :
char hello[] = "Hello\0"
and the size of your hello will be 6 instead of 5.
Finally in assembly programming we have to consider the null terminator for parameters passing in system calls. as long as the linux kernel has been written in C programming language we have to accept the rules of C programming language.
Here is the Gdb result of char hello[]
0x8049597 <hello>: 0x48 0x65 0x6c 0x6c 0x6f 0x41 0x00 0x41
0x804959f <hello+8>: 0x41 0x41 0x42 0x42 0x00 0x77 0x6f 0x72
The 0x8049597 is the start address of our string ("HelloA\0AAABB").
we put the \0 after A character. the character 'A' is equals to 0x41 hex number in Ascii table. and the \0 is 0x00.
That's why the printf function will just show 6 first characters of our string.
Upvotes: 0
Reputation: 39621
Linux uses zero terminated strings, which are the standard string format for C. The end of the string is marked by a zero byte, any bytes beyond the first zero byte in the string are not part of the string. Notably that this means that filenames cannot have a zero byte in them. (For the same reason most shellcode can't have a zero byte, as they're meant to exploit some sort of string buffer overflow.)
In practice the kernel often doesn't need to know the length of a filename, and uses functions like strcmp
which compare strings byte by byte, stopping either at the first byte that compares different or at the first zero byte encountered. If necessary however the length of a string can be computed with a function like strlen
.
Upvotes: 2