-
Notifications
You must be signed in to change notification settings - Fork 328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rework third chapter #41
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review of all files except the main post
Please adjust the descriptions also in the code sample of the third post. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review of the intro section
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftovers from the previous review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review of the "Stack operations" section
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I came here because I was quite confused by the div
instruction (where does the quotient go and what happens to the dropped number/remainder of the integer?).
Basically what I've done is fixed some of the sentence structuring and typo's related to this.
Review comments with indentation
in them means that you've used mixed indentations across lines. For example the below piece of assembly:
;; This will give us the numeric value of the character.
sub bl, 48
The comment is indented with spaces and the assembly is indented with a HARD tab \t
.
To the compiler this makes no difference but for the reader it comes off as messy.
@Yimura thank you very much for your comments, I will fix in the near time. |
thanks to @Yimura Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments to the code sample
stack/stack.asm
Outdated
mov rax, r10 | ||
;; Initialize counter by resetting it to 0. It will store the length of the result string. | ||
xor rcx, rcx | ||
;; Convert the sum from number to string to print the result on the screen. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Convert the sum from number to string to print the result on the screen. | |
;; Convert the sum from a number to a string to print the result on the screen. |
stack/stack.asm
Outdated
;; | ||
;; Print argc error | ||
;; | ||
;; Fetch the number of arguments from the stack and store it in the rcx register |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Fetch the number of arguments from the stack and store it in the rcx register | |
;; Fetch the number of arguments from the stack and store it in the rcx register. |
stack/stack.asm
Outdated
return_str: | ||
mov rcx, 10 | ||
__repeat: | ||
;; Compare the first element in the given string with the NUL terminator (end of string). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Compare the first element in the given string with the NUL terminator (end of string). | |
;; Compare the first element in the given string with the NUL terminator (end of the string). |
stack/stack.asm
Outdated
add rax, rbx | ||
;; Move to the next character in the command line argument string. | ||
inc rsi | ||
;; Repeat until we do not reach the end of the string. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Repeat until we do not reach the end of the string. | |
;; Repeat until we reach the end of the string. |
stack/stack.asm
Outdated
mov rdi, STD_IN | ||
mov rsi, rsp | ||
;; call sys_write | ||
;; Convert the sum to string and print it on the screen. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Convert the sum to string and print it on the screen. | |
;; Convert the sum to a string and print it on the screen. |
stack/stack.asm
Outdated
inc rcx | ||
;; Compare the rest of the sum with zero. | ||
cmp rax, 0x0 | ||
;; If it is not zero yet, continue to convert it to string. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; If it is not zero yet, continue to convert it to string. | |
;; If it is not zero, continue to convert it to string. |
stack/stack.asm
Outdated
cmp rax, 0x0 | ||
;; If it is not zero yet, continue to convert it to string. | ||
jne int_to_str | ||
;; Otherwise print the result. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Otherwise print the result. | |
;; Otherwise, print the result. |
stack/stack.asm
Outdated
|
||
;; Print the result to the standard output. | ||
printResult: | ||
;; Put the number of symbols within the string to the rax register. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Put the number of symbols within the string to the rax register. | |
;; Put the number of string characters to the rax register. |
stack/stack.asm
Outdated
NEW_LINE db 0xa | ||
WRONG_ARGC db "Must be two command line argument", 0xa | ||
|
||
;; Number of `sys_write` system call |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Number of `sys_write` system call | |
;; Number of the `sys_write` system call |
stack/stack.asm
Outdated
|
||
;; Number of `sys_write` system call | ||
SYS_WRITE equ 1 | ||
;; Number of `sys_exit` system call |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;; Number of `sys_exit` system call | |
;; Number of the `sys_exit` system call |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestions till "Converting integer to string"
content/asm_3.md
Outdated
As the command-line arguments of each program are represented as strings, first we need to convert our command-line arguments to numbers to calculate their sum. To convert a given string to a number, we will use a simple algorithm: | ||
|
||
1. Create an accumulator to store an intermediate result while converting the string into its numeric representation. | ||
2. Take the first byte of the string and subtract the value `48` from it. Each byte in a string is an [ASCII](https://en.wikipedia.org/wiki/ASCII) symbol with its own code. The symbol 0 has code `48`, the symbol 1 has code `49`, and so on. If we subtract `48` from the ASCII code of the given symbol, we get an integer representation of the current digit from the given string. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2. Take the first byte of the string and subtract the value `48` from it. Each byte in a string is an [ASCII](https://en.wikipedia.org/wiki/ASCII) symbol with its own code. The symbol 0 has code `48`, the symbol 1 has code `49`, and so on. If we subtract `48` from the ASCII code of the given symbol, we get an integer representation of the current digit from the given string. | |
2. Take the first byte of the string and subtract the value `48` from it. Each byte in a string is an [ASCII](https://en.wikipedia.org/wiki/ASCII) character with its own code. The character 0 has code `48`, the character 1 has code `49`, and so on. If we subtract `48` from the ASCII code of the given character, we get an integer representation of the current digit from the given string. |
content/asm_3.md
Outdated
3. As soon as we know the current digit, we multiply our accumulator from step 1 by 10 and add to it the digit that we got in step 2. | ||
4. Move to the next symbol in the given string and repeat steps 2 and 3 if it is not the end of the string (`\0` symbol). | ||
|
||
Returning to the table from the section above, we may see that pointers to the command line arguments are located on the stack right above the number of command line arguments. So if we fetch the first value from the stack after we already fetched the number of arguments, it will be a pointer to the string which is the first command line argument. If we will pop the next value from the stack, it will be the second command line argument passed to the program. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning to the table from the section above, we may see that pointers to the command line arguments are located on the stack right above the number of command line arguments. So if we fetch the first value from the stack after we already fetched the number of arguments, it will be a pointer to the string which is the first command line argument. If we will pop the next value from the stack, it will be the second command line argument passed to the program. | |
Returning to the table from the section above, we can see that pointers to the command-line arguments are located on the stack right above the number of command-line arguments. So, after we pop the number of arguments (ARGC), the stack pointer will point to the address of the first command-line argument (ARGV[0]). If we pop the next value from the stack, it will point to the second command-line argument (ARGV[1]) passed to the program. |
content/asm_3.md
Outdated
|
||
Returning to the table from the section above, we may see that pointers to the command line arguments are located on the stack right above the number of command line arguments. So if we fetch the first value from the stack after we already fetched the number of arguments, it will be a pointer to the string which is the first command line argument. If we will pop the next value from the stack, it will be the second command line argument passed to the program. | ||
|
||
Now if we will take a look at the `str_to_int` procedure it should be clear without any additional details: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now if we will take a look at the `str_to_int` procedure it should be clear without any additional details: | |
Now the `str_to_int` procedure should be more clear: |
content/asm_3.md
Outdated
``` | ||
|
||
At the start of str_to_int, we set up rax to 0 and rcx to 10. Then we go to next label. As you can see in above example (first line before first call of str_to_int) we put argv[1] in rsi from stack. Now we compare first byte of rsi with 0, because every string ends with NULL symbol and if it is we return. If it is not 0 we copy it's value to one byte bl register and substract 48 from it. Why 48? All numbers from 0 to 9 have 48 to 57 codes in asci table. So if we substract from number symbol 48 (for example from 57) we get number. Then we multiply rax on rcx (which has value - 10). After this we increment rsi for getting next byte and loop again. Algorthm is simple. For example if rsi points to '5' '7' '6' '\000' sequence, then will be following steps: | ||
As soon as we converted both command line arguments to integer numbers, we can calculate their sum: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As soon as we converted both command line arguments to integer numbers, we can calculate their sum: | |
As soon as we converted both command-line arguments to integer numbers, we can calculate their sum: |
content/asm_3.md
Outdated
|
||
After str_to_int we will have number in rax. Now let's look at int_to_str: | ||
Since we have our result, we just need to print it. But before printing it we have to convert the numeric result to string. This we will see in the next section. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have our result, we just need to print it. But before printing it we have to convert the numeric result to string. This we will see in the next section. | |
Now that we have our result, we just need to print it. But before printing it, we have to convert the numeric result back to a string. |
content/asm_3.md
Outdated
After str_to_int we will have number in rax. Now let's look at int_to_str: | ||
Since we have our result, we just need to print it. But before printing it we have to convert the numeric result to string. This we will see in the next section. | ||
|
||
### Converting integer to string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### Converting integer to string | |
### Converting an integer to a string |
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments till "Security considerations"
content/asm_3.md
Outdated
|
||
### Converting integer to string | ||
|
||
In the end of the previous section we calculated the sum of two numbers and put the result in the `r10` register. The `sys_write` system call can print only string. So we need to convert our numeric sum to string before we can print it. We will achieve this by the `int_to_str` sobroutine: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the end of the previous section we calculated the sum of two numbers and put the result in the `r10` register. The `sys_write` system call can print only string. So we need to convert our numeric sum to string before we can print it. We will achieve this by the `int_to_str` sobroutine: | |
In the previous section, we calculated the sum of two numbers and put the result in the `r10` register. As the `sys_write` system call can only print a string, now we need to convert our numeric sum into a string. To do so, we will use the `int_to_str` subroutine: |
content/asm_3.md
Outdated
``` | ||
|
||
Here we put 0 to rdx and 10 to rbx. Than we exeute div rbx. If we look above at code before str_to_int call. We will see that rax contains integer number - sum of two command line arguments. With this instruction we devide rax value on rbx value and get reminder in rdx and whole part in rax. Next we add to rdx 48 and 0x0. After adding 48 we'll get asci symbol of this number and all strings much be ended with 0x0. After this we save symbol to stack, increment r12 (it's 0 at first iteration, we set it to 0 at the _start) and compare rax with 0, if it is 0 it means that we ended to convert integer to string. Algorithm step by step is following: For example we have number 23 | ||
Before jumping to the `int_to_str` sobroutine, we need to do some preparations. As you may see we put the value of our sum in the `rax` register and initialize the counter (`rcx` register) with zero. This counter will store the number of symbols in the our future string. Note that we are using new instruction to initialize the counter - `xor`. This instruction is a [bitwise XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR) operator which resets bits of the operands to 0 if they are the same. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before jumping to the `int_to_str` sobroutine, we need to do some preparations. As you may see we put the value of our sum in the `rax` register and initialize the counter (`rcx` register) with zero. This counter will store the number of symbols in the our future string. Note that we are using new instruction to initialize the counter - `xor`. This instruction is a [bitwise XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR) operator which resets bits of the operands to 0 if they are the same. | |
Before jumping to the `int_to_str` subroutine, we must prepare the data with two instructions: | |
1. First, we put the value of our sum in the `rax` register using the `mov` instruction. | |
2. Then, we initialize the counter (`rcx` register) with zero. This counter will store the number of symbols in our future string. To initialize the counter, we use a new instruction - `xor`. This instruction is a [bitwise XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR) operator which resets bits of the operands to 0 if they are the same. |
content/asm_3.md
Outdated
push "2" to stack | ||
compare rax with 0, if yes we can finish function execution and we will have "2" "3" ... in stack | ||
``` | ||
The algorithm of the `int_to_str` sobroutine is pretty simple as well. We divide our number by `10` to get the digit and add the value `48` to the result of the division. Remember about ASCII codes? If yes it should be clear why we are doing it. As soon as we got the symbolic representation of the current digit we push it on the stack. As soon as the given digit is converted we increase our counter of numbers of symbols within the string and check our sum number. If it is zero it means we have the resulted string. If not, we just repeat the all operations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The algorithm of the `int_to_str` sobroutine is pretty simple as well. We divide our number by `10` to get the digit and add the value `48` to the result of the division. Remember about ASCII codes? If yes it should be clear why we are doing it. As soon as we got the symbolic representation of the current digit we push it on the stack. As soon as the given digit is converted we increase our counter of numbers of symbols within the string and check our sum number. If it is zero it means we have the resulted string. If not, we just repeat the all operations. | |
The algorithm of the `int_to_str` subroutine is pretty simple. We divide our number by `10` to get the digit and add the value `48` to the result of the division. Remember about the ASCII codes? If yes, it should be clear why we are doing it. As soon as we get the symbolic representation of the current digit, we push it on the stack. When the given digit is converted, we increase our counter that represents the number of characters within the string. After that, we check the sum number. If it is zero, we have the resulting string. If not, we repeat all operations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If yes, it should be clear why we are doing it:
- As soon as we get the symbolic representation of the current digit, we push it on the stack.
- When the given digit is converted, we increase our counter that represents the number of characters within the string.
- After that, we check the sum number. If it is zero, we have the resulting string. If not, we repeat all operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ consider the alternative formating of text in the form of ordered list
content/asm_3.md
Outdated
|
||
We implemented two useful function `int_to_str` and `str_to_int` for converting integer number to string and vice versa. Now we have sum of two integers which was converted into string and saved in the stack. We can print result: | ||
As soon as we will collect all the digits of our sum, they will be stored on the stack. So we can print our string with the following code: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As soon as we will collect all the digits of our sum, they will be stored on the stack. So we can print our string with the following code: | |
Once we collect all the digits of the sum, they will be stored on the stack. Now we can print the string using the following code: |
syscall | ||
``` | ||
|
||
That's All. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:)
content/asm_3.md
Outdated
syscall | ||
``` | ||
|
||
That's All. | ||
Most of this code should be already well understandable for you as the most significant part of it consists of the initialization of data for the call of the `sys_write` and `sys_exit` exit calls. The most interesting part should be first four lines of code of the `printResult` subroutine. As you may remember the one of the parameters of the `sys_write` system call is a length of the string that we want to print on the screen. We have this number as we maintained a counter of symbols during converting the numeric sum to the string. This counter was stored in the `rcx` register. Our string is located on the stack. We pushed each digit with the `push` operator. But the `push` operator pushes `64` bits (or `8` bytes) while our symbol is only 1 byte. To get the whole length of the string for printing, we should multiple the number of symbols to `8`. This will give us the length of the string that we can use as a third argument of the `sys_write` system call. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of this code should be already well understandable for you as the most significant part of it consists of the initialization of data for the call of the `sys_write` and `sys_exit` exit calls. The most interesting part should be first four lines of code of the `printResult` subroutine. As you may remember the one of the parameters of the `sys_write` system call is a length of the string that we want to print on the screen. We have this number as we maintained a counter of symbols during converting the numeric sum to the string. This counter was stored in the `rcx` register. Our string is located on the stack. We pushed each digit with the `push` operator. But the `push` operator pushes `64` bits (or `8` bytes) while our symbol is only 1 byte. To get the whole length of the string for printing, we should multiple the number of symbols to `8`. This will give us the length of the string that we can use as a third argument of the `sys_write` system call. | |
Most of this code should already be understandable, as it mainly consists of the data initialization for the `sys_write` and `sys_exit` system calls. The most interesting part is the first four lines of the `printResult` subroutine. As you may remember, one of the parameters of the `sys_write` system call is the length of the string we want to print on the screen. We have this number because we maintained a counter of characters while converting the numeric sum to a string. This counter was stored in the `rcx` register. Our string is located on the stack, where we pushed each digit using the `push` operator. However, the `push` operator pushes `64` bits (or `8` bytes), while our symbol is only 1 byte. To calculate the total length of the string for printing, we should multiply the number of symbols by `8`. This will give us the length of the string that we can use as the third argument of the `sys_write` system call. |
content/asm_3.md
Outdated
That's All. | ||
Most of this code should be already well understandable for you as the most significant part of it consists of the initialization of data for the call of the `sys_write` and `sys_exit` exit calls. The most interesting part should be first four lines of code of the `printResult` subroutine. As you may remember the one of the parameters of the `sys_write` system call is a length of the string that we want to print on the screen. We have this number as we maintained a counter of symbols during converting the numeric sum to the string. This counter was stored in the `rcx` register. Our string is located on the stack. We pushed each digit with the `push` operator. But the `push` operator pushes `64` bits (or `8` bytes) while our symbol is only 1 byte. To get the whole length of the string for printing, we should multiple the number of symbols to `8`. This will give us the length of the string that we can use as a third argument of the `sys_write` system call. | ||
|
||
As soon as all parameters of the system calls are ready, we can pass them as arguments to print the sum and print new line after it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As soon as all parameters of the system calls are ready, we can pass them as arguments to print the sum and print new line after it. | |
Once all parameters of both system calls are ready, we can pass them as arguments to print the sum followed by a new line. |
content/asm_3.md
Outdated
|
||
As soon as all parameters of the system calls are ready, we can pass them as arguments to print the sum and print new line after it. | ||
|
||
Let's build our program with the usual commands: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's build our program with the usual commands: | |
Now, let's build our program with the usual commands: |
content/asm_3.md
Outdated
$ ld -o stack stack.o | ||
``` | ||
|
||
And try to run it: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And try to run it: | |
Then, try to run it: |
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
content/asm_3.md
Outdated
|
||
## Security considerations | ||
|
||
As we have seen in this and in the previous posts, the stack is a crucial concept that is used to manage function calls in our programs. Understanding of how the stack memory managed is not only important for writing programs with re-usable functions but also crucial for writing secure programs. The stack often has been a common source of security vulnerabilities, especially in low-level code and assembly routines. When you use `call` and `ret` instructions, the processor doesn’t verify if the return address is valid, but it just simply pops the address and jumps on it. One of the most common problems is the [stack overflow](https://en.wikipedia.org/wiki/Stack_overflow). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we have seen in this and in the previous posts, the stack is a crucial concept that is used to manage function calls in our programs. Understanding of how the stack memory managed is not only important for writing programs with re-usable functions but also crucial for writing secure programs. The stack often has been a common source of security vulnerabilities, especially in low-level code and assembly routines. When you use `call` and `ret` instructions, the processor doesn’t verify if the return address is valid, but it just simply pops the address and jumps on it. One of the most common problems is the [stack overflow](https://en.wikipedia.org/wiki/Stack_overflow). | |
As seen in this and the previous posts, the stack is a crucial concept used to manage function calls in our programs. Understanding how the stack memory is managed is important for writing programs with reusable functions and crucial for writing secure programs. The stack is a common source of security vulnerabilities, especially in low-level code and assembly routines. When you use `call` and `ret` instructions, the processor doesn’t verify if the return address is valid, but it just simply pops the address and jumps on it. One of the most common problems is the [stack overflow](https://en.wikipedia.org/wiki/Stack_overflow). |
content/asm_3.md
Outdated
|
||
As we have seen in this and in the previous posts, the stack is a crucial concept that is used to manage function calls in our programs. Understanding of how the stack memory managed is not only important for writing programs with re-usable functions but also crucial for writing secure programs. The stack often has been a common source of security vulnerabilities, especially in low-level code and assembly routines. When you use `call` and `ret` instructions, the processor doesn’t verify if the return address is valid, but it just simply pops the address and jumps on it. One of the most common problems is the [stack overflow](https://en.wikipedia.org/wiki/Stack_overflow). | ||
|
||
Let's take a look at the simple C function (the function is written on C for simplicity): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's take a look at the simple C function (the function is written on C for simplicity): | |
Let's take a look at the simple C function: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would remove that part; if you decide to keep it, correct the preposition -> written in C
content/asm_3.md
Outdated
} | ||
``` | ||
|
||
If we will try to build this program and run it, we'll see the following error instead of the *Program exited successfully* string: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we will try to build this program and run it, we'll see the following error instead of the *Program exited successfully* string: | |
If we build and run this program, we'll see the following error instead of the `Program exited successfully` string: |
content/asm_3.md
Outdated
Aborted (core dumped) | ||
``` | ||
|
||
The reason for this is that we put on the stack the value which is bigger than our 8 bytes buffer. Happily instead of overwriting of return address or segmentation fault error we have got "stack smashing detected" error. This check is done by the modern compiler to prevent overwriting of critical data. There are other techniques in modern compilers and operating system kernels to mitigate vulnerabilities related to stack, like: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for this is that we put on the stack the value which is bigger than our 8 bytes buffer. Happily instead of overwriting of return address or segmentation fault error we have got "stack smashing detected" error. This check is done by the modern compiler to prevent overwriting of critical data. There are other techniques in modern compilers and operating system kernels to mitigate vulnerabilities related to stack, like: | |
The reason for this error is that we put on the stack a value bigger than our 8-byte buffer. Happily, instead of overwriting the return address or segmentation fault error, we get a `stack smashing detected` error. This check is done by a modern compiler to prevent overwriting critical data. There are also other techniques in modern compilers and operating system kernels to mitigate vulnerabilities related to stack, like: |
content/asm_3.md
Outdated
- [Non-executable stack](https://en.wikipedia.org/wiki/Executable-space_protection) | ||
- And others... | ||
|
||
In any cases, despite all of these techniques may help you to protect your programs from stack related errors, you should be careful, especially with the data that your program receives from outside. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any cases, despite all of these techniques may help you to protect your programs from stack related errors, you should be careful, especially with the data that your program receives from outside. | |
Despite all of these techniques may help you to protect your programs from stack-related errors, you should be careful, especially with the external data that your program receives. |
content/asm_3.md
Outdated
This example might be a little bit artificial as unlikely you are going to use the `gets` function in your code. The [manual page](https://man7.org/linux/man-pages/man3/gets.3.html) of this function says: | ||
|
||
> Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead. | ||
|
||
Moreover this function is deprecated. But despite such artificial example, there can be real danger even if you are not using deprecated functions and use all the options of the compiler that help you to protect your program. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example might be a little bit artificial as unlikely you are going to use the `gets` function in your code. The [manual page](https://man7.org/linux/man-pages/man3/gets.3.html) of this function says: | |
> Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead. | |
Moreover this function is deprecated. But despite such artificial example, there can be real danger even if you are not using deprecated functions and use all the options of the compiler that help you to protect your program. | |
This example might seem a bit artificial as unlikely you are going to use the deprecated `gets` function. However, even with such an unrealistic example, real risks still exist — even if you avoid deprecated functions and use all the compiler’s safety features to protect your program. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
too much "screen time" for gets
content/asm_3.md
Outdated
|
||
Moreover this function is deprecated. But despite such artificial example, there can be real danger even if you are not using deprecated functions and use all the options of the compiler that help you to protect your program. | ||
|
||
The real world case when a wrong memory management led to serious consequences is [CVE-2017-1000253](https://nvd.nist.gov/vuln/detail/CVE-2017-1000253). This vulnerability was found in the Linux kernel and led to the [privilege escalation](https://en.wikipedia.org/wiki/Privilege_escalation). When the kernel runs a process, it needs to perform many different operations. One of such operations are to load the program into memory and initialize the stack. The binary itself is loaded and located below the stack memory. Besides that, there is a gap which is 128 megabytes. The loading of a big enough binary led to the situation when certain segments of the binary were loaded and mapped to this gap. The binaries with the big enough data segements (bingger than 128 megabytes) can end up mapped over the stack memory. All of this may lead to the situation when the [ELF .dynamic section](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) is overwritten by the stack. One may put a path to a shared library that will be loaded by the kernel and the code executed with the higher privileges. If you are interested in more details you can read the [report](https://www.qualys.com/2017/09/26/linux-pie-cve-2017-1000253/cve-2017-1000253.txt) and the [fix](https://github.com/torvalds/linux/commit/a87938b2e246b81b4fb713edb371a9fa3c5c3c86). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The real world case when a wrong memory management led to serious consequences is [CVE-2017-1000253](https://nvd.nist.gov/vuln/detail/CVE-2017-1000253). This vulnerability was found in the Linux kernel and led to the [privilege escalation](https://en.wikipedia.org/wiki/Privilege_escalation). When the kernel runs a process, it needs to perform many different operations. One of such operations are to load the program into memory and initialize the stack. The binary itself is loaded and located below the stack memory. Besides that, there is a gap which is 128 megabytes. The loading of a big enough binary led to the situation when certain segments of the binary were loaded and mapped to this gap. The binaries with the big enough data segements (bingger than 128 megabytes) can end up mapped over the stack memory. All of this may lead to the situation when the [ELF .dynamic section](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) is overwritten by the stack. One may put a path to a shared library that will be loaded by the kernel and the code executed with the higher privileges. If you are interested in more details you can read the [report](https://www.qualys.com/2017/09/26/linux-pie-cve-2017-1000253/cve-2017-1000253.txt) and the [fix](https://github.com/torvalds/linux/commit/a87938b2e246b81b4fb713edb371a9fa3c5c3c86). | |
The real-world case when wrong memory management led to serious consequences is [CVE-2017-1000253](https://nvd.nist.gov/vuln/detail/CVE-2017-1000253). This vulnerability was found in the Linux kernel and led to the [privilege escalation](https://en.wikipedia.org/wiki/Privilege_escalation). When the kernel runs a process, it needs to perform many different operations, such as loading the program into memory and initializing the stack. After the program is loaded and stack initialized, the program is located below the stack memory, with a 128-megabyte gap between them. However, when a large program is loaded, it can overwrite the stack memory. Under certain conditions, it may lead to privilege escalation. If you are interested in more details, you can read the [report](https://www.qualys.com/2017/09/26/linux-pie-cve-2017-1000253/cve-2017-1000253.txt) and the [fix](https://github.com/torvalds/linux/commit/a87938b2e246b81b4fb713edb371a9fa3c5c3c86). |
content/asm_3.md
Outdated
|
||
The real world case when a wrong memory management led to serious consequences is [CVE-2017-1000253](https://nvd.nist.gov/vuln/detail/CVE-2017-1000253). This vulnerability was found in the Linux kernel and led to the [privilege escalation](https://en.wikipedia.org/wiki/Privilege_escalation). When the kernel runs a process, it needs to perform many different operations. One of such operations are to load the program into memory and initialize the stack. The binary itself is loaded and located below the stack memory. Besides that, there is a gap which is 128 megabytes. The loading of a big enough binary led to the situation when certain segments of the binary were loaded and mapped to this gap. The binaries with the big enough data segements (bingger than 128 megabytes) can end up mapped over the stack memory. All of this may lead to the situation when the [ELF .dynamic section](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) is overwritten by the stack. One may put a path to a shared library that will be loaded by the kernel and the code executed with the higher privileges. If you are interested in more details you can read the [report](https://www.qualys.com/2017/09/26/linux-pie-cve-2017-1000253/cve-2017-1000253.txt) and the [fix](https://github.com/torvalds/linux/commit/a87938b2e246b81b4fb713edb371a9fa3c5c3c86). | ||
|
||
As we've seen, subtle bugs in stack layout can lead to serious vulnerabilities. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we've seen, subtle bugs in stack layout can lead to serious vulnerabilities. | |
As you can see, subtle bugs in stack layout can lead to serious vulnerabilities. |
content/asm_3.md
Outdated
|
||
## Conclusion | ||
|
||
We’ve just written our third program using assembly — great job 🎉 In the next post, we’ll continue exploring assembly programming and see more details how to work with strings. If you have any questions or thoughts, feel free to reach out. See you in the next post! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We’ve just written our third program using assembly — great job 🎉 In the next post, we’ll continue exploring assembly programming and see more details how to work with strings. If you have any questions or thoughts, feel free to reach out. See you in the next post! | |
We’ve just written our third program using assembly — great job 🎉 In the next post, we’ll continue exploring assembly programming and see more details on how to work with strings. If you have any questions or thoughts, feel free to reach out. See you in the next post! |
Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
Description
This PR provides rework of the third chapter.