Calling execle from the libc crate always throws Bad Address

Hello everyone !

The code

unsafe {
    let shell = CString::new("/bin/bash").unwrap();
    let env = CString::new("TERM=dumb").unwrap();

    if libc::execle(shell.as_c_str().as_ptr(), env.as_c_str().as_ptr()) == -1 {
        println!("ERROR execle() ({})", errno::errno());
    }
}

throws bad address. What should I do to successfully execute /bin/bash ?

env should be an array of null terminated strings. Here, it's just a string and an additional (at least one) arg is required

execle takes a variable number of parameters: file, each program arg0 through argN, NULL ending arguments, then the environment -- and that needs to be an array of c-strings also terminated by NULL.

1 Like

Like this then ?

if libc::execle(shell.as_c_str().as_ptr(), shell.as_c_str().as_ptr(), std::ptr::null(), env.as_c_str().as_ptr(), std::ptr::null()) == -1 {
    println!("ERROR execle() ({})", errno::errno());
}
libc::execle(shell.as_c_str().as_ptr(), shell.as_c_str().as_ptr(), std::ptr::null() as *const c_void, env.as_c_str().as_ptr(), std::ptr::null() as *const c_void)

This still throws bad address

env has to be a pointer to an array of pointers. First create an array of pointers, then pass a pointer to it:

let shell = CString::new("/bin/bash").unwrap();
let term = CString::new("TERM=dumb").unwrap();
let env = [term.as_ptr(), ptr::null()]; // null-terminated array

libc::execle(shell.as_ptr(), ptr::null(), env.as_ptr())
1 Like

Here's a similar example using execve:
Note There must be a first argument, and it is usually set to the program's name.

use libc::execve;
use std::iter::once;
use std::ptr::null;
use std::ffi::CString;

fn main() {
    let prog = CString::new("/bin/sh").unwrap();
    let args: Vec<CString> = ["sh", "-c", "id"].iter().map(|&b| CString::new(b).unwrap()).collect();
    let env: Vec<CString> = ["TERM=dumb"].iter().map(|&b| CString::new(b).unwrap()).collect();
    
    let args: Vec<*const i8> = args.iter().map(|s| s.as_c_str().as_ptr()).chain(once(null())).collect();
    let env: Vec<*const i8> = env.iter().map(|s| s.as_c_str().as_ptr()).chain(once(null())).collect();

    unsafe {
        execve(prog.as_c_str().as_ptr(), args.as_slice().as_ptr(), env.as_slice().as_ptr());
    }
}
1 Like

Still doesn't work.
Tried this code (yours but with an argument)

let shell = CString::new("/bin/bash").unwrap();
let arg0 = shell.clone();
let term = CString::new("TERM=dumb").unwrap();
let args = [arg0.as_ptr(), ptr::null()];
let env = [term.as_ptr(), ptr::null()];

if libc::execle(shell.as_ptr(), args.as_ptr() as *const i8, env.as_ptr()) == -1 {
    println!("ERROR execle() ({})", errno::errno());
}

And this (a copy of yours)

let shell = CString::new("/bin/bash").unwrap();
let term = CString::new("TERM=dumb").unwrap();
let env = [term.as_ptr(), ptr::null()];

if libc::execle(shell.as_ptr(), ptr::null(), env.as_ptr()) == -1 {
    println!("ERROR execle() ({})", errno::errno());
}

Still says the same, bad address.

Tried that and it worked !!

let shell = CString::new("/bin/bash").unwrap();
let arg0 = shell.clone();
let term = CString::new("TERM=dumb").unwrap();
let env = [term.as_ptr(), ptr::null()];

if libc::execle(shell.as_ptr(), arg0.as_ptr(), ptr::null() as *const c_void, env.as_ptr()) == -1 {
    println!("ERROR execle() ({})", errno::errno());
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.