Home > OS >  Unable to perform execve syscall in RISC V assembly
Unable to perform execve syscall in RISC V assembly

Time:06-20

I am trying to perform the execve syscall via assembly. Before I start, I have downloaded the riscv toolchain from the github repo, and configured it using: ./configure /opt/rv32./configure --prefix=/opt/rv32 --with-arch=rv32ia --with-abi=ilp32. In order to execute the binaries, I'm using qemu-user (qemu-riscv32). Ok, so first I wrote a simple C program that performs an execve syscall. The code is the following:

#include <unistd.h>

char *args[] = {"/bin/sh", 0x0};

int main()
{
    execve(args[0], args, 0x0);
}

Then I dissassembled the produced code, and what I obtained is:

00010530 <main>:
   10530:   ff010113            addi    sp,sp,-16
   10534:   00112623            sw  ra,12(sp)
   10538:   00812423            sw  s0,8(sp)
   1053c:   01010413            addi    s0,sp,16
   10540:   a9418793            addi    a5,gp,-1388 # 85df0 <args>
   10544:   0007a703            lw  a4,0(a5)
   10548:   00000613            li  a2,0
   1054c:   a9418593            addi    a1,gp,-1388 # 85df0 <args>
   10550:   00070513            mv  a0,a4
   10554:   304160ef            jal ra,26858 <__execve>
   10558:   00000793            li  a5,0
   1055c:   00078513            mv  a0,a5
   10560:   00c12083            lw  ra,12(sp)
   10564:   00812403            lw  s0,8(sp)
   10568:   01010113            addi    sp,sp,16
   1056c:   00008067            ret

00026858 <__execve>:
   26858:   0dd00893            li  a7,221
   2685c:   00000073            ecall
   26860:   fffff8b7            lui a7,0xfffff
   26864:   00a8e463            bltu    a7,a0,2686c <__execve 0x14>
   26868:   00008067            ret
   2686c:   71d0406f            j   2b788 <__syscall_error>
   26870:   00008067            ret

Notice that the code has been compiled using -static flag

Then I tried to write my assembly program that basically does the same, so I ended up with the following code:

.globl _start
.section .text

_start:
    # execve syscall
    la a0, shell # Pointer to '/bin/sh'
    la a1, addr # Pointer to the arraythat contains '/bin/sh'
    sw a0, 0(a1)
    mv a2, x0 # No environment variables are needed
    li a7, 0xDD # 221
    ecall
    # exit syscall
    li a7, 0x5D # 93
    ecall

.section .rodata
shell: .string "/bin/sh"
.section .data
addr: .space 4

Then, I compiled the code with the following statement: riscv32-unknown-linux-gnu-gcc -c syscall.s && riscv32-unknown-linux-gnu-ld syscall.o -o syscall And now, when I try to execute my C code, it works perfectly, even compiling the code without -static flag, but when I execute my assembly code it returns 242 as error code. Before that, I have been checking errno codes produced by a failed execve, but i found nothing. In addition, I have been searching if someone has experienced the same problem but unfortunately anyone has. Any idea? Is there something am I missing or am I wrong? Thanks

CodePudding user response:

You're not telling the kernel how many entries there are in the argv array. The rule is that argv needs to be an array of pointers whose last entry is a NULL pointer. This would also be true for the envp argument if you were supplying an envp.

I'd suggest you do this with a preinitialized array also in .rodata, like so:

    .section .rodata
shell:
    .string "/bin/sh"
    .balign 4
argv:
    .4byte shell
    .4byte 0

and then your code can be something like

    .section .text
    .globl _start
    .type _start, @function
_start:
    # execve syscall
    la a0, shell # Pointer to '/bin/sh'
    la a1, addr  # Pointer to the array that contains '/bin/sh'
    li a2, 0     # No environment variables
    li a7, 0xDD  # 221 = execve
    ecall
    # _exit syscall
    # if execve returns, it failed, so pass 1 to _exit
    li a0, 1
    li a7, 0x5D  # 93 = _exit
    ecall
  • Related