-1

I have the following Python script that I'd like to execute with the permissions afforded by the setuid/setgid bit:

#!/usr/bin/env python3
from mypackage.cli import main as cli_main
cli_main()

However: I would like execute the command directly from a C wrapper without an intermediate Python script file.

I've tried doing this using execve as follows:

#include <stdlib.h>
#include <string.h>
#include <unistd.h>

const char *ENV = "/usr/bin/env";
const char *ENV_ARGS[] = { "python3", "-c", "from mypackage.cli import main as cli_main; cli_main()" };
const int NUM_ENV_ARGS = 3;

int main(int argc, char *argv[], char *envp[]) {
    int total_num_args = (argc - 1) + NUM_ENV_ARGS + 1;

    // Create an array of strings to hold the final arg list.
    // No need to free the malloc'ed memory as it will be freed if execve succeeds,
    // or when the program exits if execve fails.
    char **final_args = (char **)malloc(total_num_args * sizeof(char *));
    if (final_args == NULL) {
        return 1;
    }

    // Copy the invocation and the arguments to this program into the final arg list.
    memcpy(final_args, ENV_ARGS, NUM_ENV_ARGS * sizeof(char *));
    memcpy(final_args + NUM_ENV_ARGS, argv + 1, (argc - 1) * sizeof(char *));
    final_args[total_num_args - 1] = NULL;

    return execve(ENV, final_args, envp);
}

But I get the following error when I run the compiled program as ./mycli foo bar:

python3: illegal option -- c
usage: env [-iv] [-P utilpath] [-S string] [-u name]
           [name=value ...] [utility [argument ...]]

How can I accomplish this?

DanielGibbs
  • 9,910
  • 11
  • 76
  • 121

2 Answers2

1

You're not running the python3 command. You're running the env command. The ENV variable should contain /usr/bin/python3, or whatever you path to python3 is.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • The environment variables are passed through from the caller to the `execve` call so `env` gets the same variables that it would have if I called it directly from the command line. – DanielGibbs Dec 05 '16 at 20:31
  • @DanielGibbs No, those environment variables are in`envp`. There's no need to call `env`. – dbush Dec 05 '16 at 20:33
  • So what would I change to make it work? I'd like to use `env` as I can't guarantee where the `python3` executable is located. – DanielGibbs Dec 05 '16 at 20:44
  • @DanielGibbs if you know `python3` is on the path, just use `const char *ENV = "python3"`. Then use `execvp`, which searches the path, instead of `execve`. – dbush Dec 05 '16 at 20:49
  • "The other functions take the environment for the new process image from the external variable environ in the calling process." That must've been the bit I missed in the man page. – DanielGibbs Dec 05 '16 at 21:30
1

You are constructing your argument array incorrectly. It should correspond exactly to the exec'ed program's argv array, including that the 0th element designates the name of the program, which in this case would conventionally be "env" or "/usr/bin/env". Because you skip the "env", env is interpreting "python3" as its own name, as evidenced by the error message. That message comes from env, not from Python.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157