Move remaining code from subprocess.{h,c} to more appropriate places.

This patch moves the remaining code from subprocess.{h,c} to more
appropriate places in the process.c and process_win32.c module.

We also delete the now empty subprocess module files.

See: https://bugs.torproject.org/28179
This commit is contained in:
Alexander Færøy 2018-11-26 06:14:47 +01:00 committed by Nick Mathewson
parent f7d13425fc
commit ccc1963890
13 changed files with 171 additions and 240 deletions

View file

@ -142,7 +142,7 @@
#include "lib/process/pidfile.h"
#include "lib/process/restrict.h"
#include "lib/process/setuid.h"
#include "lib/process/subprocess.h"
#include "lib/process/process.h"
#include "lib/net/gethostname.h"
#include "lib/thread/numcpus.h"

View file

@ -103,7 +103,6 @@
#include "feature/control/control.h"
#include "lib/process/process.h"
#include "lib/process/subprocess.h"
#include "lib/process/env.h"
static smartlist_t *

View file

@ -14,7 +14,6 @@ src_lib_libtor_process_a_SOURCES = \
src/lib/process/process_win32.c \
src/lib/process/restrict.c \
src/lib/process/setuid.c \
src/lib/process/subprocess.c \
src/lib/process/waitpid.c \
src/lib/process/winprocess_sys.c
@ -32,6 +31,5 @@ noinst_HEADERS += \
src/lib/process/process_win32.h \
src/lib/process/restrict.h \
src/lib/process/setuid.h \
src/lib/process/subprocess.h \
src/lib/process/waitpid.h \
src/lib/process/winprocess_sys.h

View file

@ -26,6 +26,12 @@
/** A list of all <b>process_t</b> instances currently allocated. */
static smartlist_t *processes;
/**
* Boolean. If true, then Tor may call execve or CreateProcess via
* tor_spawn_background.
**/
static int may_spawn_background_process = 1;
/** Structure to represent a child process. */
struct process_t {
/** Process status. */
@ -114,6 +120,16 @@ process_protocol_to_string(process_protocol_t protocol)
/* LCOV_EXCL_STOP */
}
/**
* Turn off may_spawn_background_process, so that all future calls to
* tor_spawn_background are guaranteed to fail.
**/
void
tor_disable_spawning_background_processes(void)
{
may_spawn_background_process = 0;
}
/** Initialize the Process subsystem. This function initializes the Process
* subsystem's global state. For cleaning up, <b>process_free_all()</b> should
* be called. */
@ -234,6 +250,9 @@ process_exec(process_t *process)
{
tor_assert(process);
if (BUG(may_spawn_background_process == 0))
return PROCESS_STATUS_ERROR;
process_status_t status = PROCESS_STATUS_NOT_RUNNING;
log_info(LD_PROCESS, "Starting new process: %s", process->command);

View file

@ -45,6 +45,8 @@ typedef enum {
const char *process_protocol_to_string(process_protocol_t protocol);
void tor_disable_spawning_background_processes(void);
struct process_t;
typedef struct process_t process_t;

View file

@ -18,13 +18,16 @@
#include "lib/log/win32err.h"
#include "lib/process/process.h"
#include "lib/process/process_win32.h"
#include "lib/process/subprocess.h"
#include "lib/process/env.h"
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef _WIN32
/** The size of our intermediate buffers. */
@ -889,4 +892,104 @@ process_win32_handle_read_completion(process_win32_handle_t *handle,
return false;
}
/** Format a single argument for being put on a Windows command line.
* Returns a newly allocated string */
STATIC char *
format_win_cmdline_argument(const char *arg)
{
char *formatted_arg;
char need_quotes;
const char *c;
int i;
int bs_counter = 0;
/* Backslash we can point to when one is inserted into the string */
const char backslash = '\\';
/* Smartlist of *char */
smartlist_t *arg_chars;
arg_chars = smartlist_new();
/* Quote string if it contains whitespace or is empty */
need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]);
/* Build up smartlist of *chars */
for (c=arg; *c != '\0'; c++) {
if ('"' == *c) {
/* Double up backslashes preceding a quote */
for (i=0; i<(bs_counter*2); i++)
smartlist_add(arg_chars, (void*)&backslash);
bs_counter = 0;
/* Escape the quote */
smartlist_add(arg_chars, (void*)&backslash);
smartlist_add(arg_chars, (void*)c);
} else if ('\\' == *c) {
/* Count backslashes until we know whether to double up */
bs_counter++;
} else {
/* Don't double up slashes preceding a non-quote */
for (i=0; i<bs_counter; i++)
smartlist_add(arg_chars, (void*)&backslash);
bs_counter = 0;
smartlist_add(arg_chars, (void*)c);
}
}
/* Don't double up trailing backslashes */
for (i=0; i<bs_counter; i++)
smartlist_add(arg_chars, (void*)&backslash);
/* Allocate space for argument, quotes (if needed), and terminator */
const size_t formatted_arg_len = smartlist_len(arg_chars) +
(need_quotes ? 2 : 0) + 1;
formatted_arg = tor_malloc_zero(formatted_arg_len);
/* Add leading quote */
i=0;
if (need_quotes)
formatted_arg[i++] = '"';
/* Add characters */
SMARTLIST_FOREACH(arg_chars, char*, ch,
{
formatted_arg[i++] = *ch;
});
/* Add trailing quote */
if (need_quotes)
formatted_arg[i++] = '"';
formatted_arg[i] = '\0';
smartlist_free(arg_chars);
return formatted_arg;
}
/** Format a command line for use on Windows, which takes the command as a
* string rather than string array. Follows the rules from "Parsing C++
* Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the
* Python subprocess module. Returns a newly allocated string */
STATIC char *
tor_join_win_cmdline(const char *argv[])
{
smartlist_t *argv_list;
char *joined_argv;
int i;
/* Format each argument and put the result in a smartlist */
argv_list = smartlist_new();
for (i=0; argv[i] != NULL; i++) {
smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i]));
}
/* Join the arguments with whitespace */
joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL);
/* Free the newly allocated arguments, and the smartlist */
SMARTLIST_FOREACH(argv_list, char *, arg,
{
tor_free(arg);
});
smartlist_free(argv_list);
return joined_argv;
}
#endif /* ! defined(_WIN32). */

View file

@ -86,6 +86,9 @@ STATIC int process_win32_read_from_handle(process_win32_handle_t *,
STATIC bool process_win32_handle_read_completion(process_win32_handle_t *,
DWORD,
DWORD);
STATIC char *format_win_cmdline_argument(const char *arg);
STATIC char *tor_join_win_cmdline(const char *argv[]);
#endif /* defined(PROCESS_WIN32_PRIVATE). */
#endif /* ! defined(_WIN32). */

View file

@ -1,158 +0,0 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file subprocess.c
* \brief Launch and monitor other processes.
**/
#define SUBPROCESS_PRIVATE
#include "lib/process/subprocess.h"
#include "lib/container/smartlist.h"
#include "lib/err/torerr.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/log/win32err.h"
#include "lib/malloc/malloc.h"
#include "lib/process/env.h"
#include "lib/process/waitpid.h"
#include "lib/string/compat_ctype.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <errno.h>
#include <string.h>
/** Format a single argument for being put on a Windows command line.
* Returns a newly allocated string */
static char *
format_win_cmdline_argument(const char *arg)
{
char *formatted_arg;
char need_quotes;
const char *c;
int i;
int bs_counter = 0;
/* Backslash we can point to when one is inserted into the string */
const char backslash = '\\';
/* Smartlist of *char */
smartlist_t *arg_chars;
arg_chars = smartlist_new();
/* Quote string if it contains whitespace or is empty */
need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]);
/* Build up smartlist of *chars */
for (c=arg; *c != '\0'; c++) {
if ('"' == *c) {
/* Double up backslashes preceding a quote */
for (i=0; i<(bs_counter*2); i++)
smartlist_add(arg_chars, (void*)&backslash);
bs_counter = 0;
/* Escape the quote */
smartlist_add(arg_chars, (void*)&backslash);
smartlist_add(arg_chars, (void*)c);
} else if ('\\' == *c) {
/* Count backslashes until we know whether to double up */
bs_counter++;
} else {
/* Don't double up slashes preceding a non-quote */
for (i=0; i<bs_counter; i++)
smartlist_add(arg_chars, (void*)&backslash);
bs_counter = 0;
smartlist_add(arg_chars, (void*)c);
}
}
/* Don't double up trailing backslashes */
for (i=0; i<bs_counter; i++)
smartlist_add(arg_chars, (void*)&backslash);
/* Allocate space for argument, quotes (if needed), and terminator */
const size_t formatted_arg_len = smartlist_len(arg_chars) +
(need_quotes ? 2 : 0) + 1;
formatted_arg = tor_malloc_zero(formatted_arg_len);
/* Add leading quote */
i=0;
if (need_quotes)
formatted_arg[i++] = '"';
/* Add characters */
SMARTLIST_FOREACH(arg_chars, char*, ch,
{
formatted_arg[i++] = *ch;
});
/* Add trailing quote */
if (need_quotes)
formatted_arg[i++] = '"';
formatted_arg[i] = '\0';
smartlist_free(arg_chars);
return formatted_arg;
}
/** Format a command line for use on Windows, which takes the command as a
* string rather than string array. Follows the rules from "Parsing C++
* Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the
* Python subprocess module. Returns a newly allocated string */
char *
tor_join_win_cmdline(const char *argv[])
{
smartlist_t *argv_list;
char *joined_argv;
int i;
/* Format each argument and put the result in a smartlist */
argv_list = smartlist_new();
for (i=0; argv[i] != NULL; i++) {
smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i]));
}
/* Join the arguments with whitespace */
joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL);
/* Free the newly allocated arguments, and the smartlist */
SMARTLIST_FOREACH(argv_list, char *, arg,
{
tor_free(arg);
});
smartlist_free(argv_list);
return joined_argv;
}
/**
* Boolean. If true, then Tor may call execve or CreateProcess via
* tor_spawn_background.
**/
static int may_spawn_background_process = 1;
/**
* Turn off may_spawn_background_process, so that all future calls to
* tor_spawn_background are guaranteed to fail.
**/
void
tor_disable_spawning_background_processes(void)
{
may_spawn_background_process = 0;
}

View file

@ -1,20 +0,0 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file subprocess.h
* \brief Header for subprocess.c
**/
#ifndef TOR_SUBPROCESS_H
#define TOR_SUBPROCESS_H
void tor_disable_spawning_background_processes(void);
#ifndef _WIN32
char *tor_join_win_cmdline(const char *argv[]);
#endif
#endif

View file

@ -9,7 +9,6 @@
#include "lib/err/torerr.h"
#include "lib/log/log.h"
#include "test/test.h"
#include "lib/process/subprocess.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>

View file

@ -628,11 +628,51 @@ test_win32(void *arg)
process_init();
process_t *process = process_new("");
char *joined_argv = NULL;
/* On Win32 all processes should have a Win32 process handle. */
tt_ptr_op(NULL, OP_NE, process_get_win32_process(process));
/* Based on some test cases from "Parsing C++ Command-Line Arguments" in
* MSDN but we don't exercise all quoting rules because tor_join_win_cmdline
* will try to only generate simple cases for the child process to parse;
* i.e. we never embed quoted strings in arguments. */
const char *argvs[][4] = {
{"a", "bb", "CCC", NULL}, // Normal
{NULL, NULL, NULL, NULL}, // Empty argument list
{"", NULL, NULL, NULL}, // Empty argument
{"\"a", "b\"b", "CCC\"", NULL}, // Quotes
{"a\tbc", "dd dd", "E", NULL}, // Whitespace
{"a\\\\\\b", "de fg", "H", NULL}, // Backslashes
{"a\\\"b", "\\c", "D\\", NULL}, // Backslashes before quote
{"a\\\\b c", "d", "E", NULL}, // Backslashes not before quote
{ NULL } // Terminator
};
const char *cmdlines[] = {
"a bb CCC",
"",
"\"\"",
"\\\"a b\\\"b CCC\\\"",
"\"a\tbc\" \"dd dd\" E",
"a\\\\\\b \"de fg\" H",
"a\\\\\\\"b \\c D\\",
"\"a\\\\b c\" d E",
NULL // Terminator
};
int i;
for (i=0; cmdlines[i]!=NULL; i++) {
log_info(LD_GENERAL, "Joining argvs[%d], expecting <%s>", i, cmdlines[i]);
joined_argv = tor_join_win_cmdline(argvs[i]);
tt_str_op(cmdlines[i],OP_EQ, joined_argv);
tor_free(joined_argv);
}
done:
tor_free(joined_argv);
process_free(process);
process_free_all();
#endif

View file

@ -8,7 +8,6 @@
#define UTIL_PRIVATE
#define STATEFILE_PRIVATE
#define CONTROL_PRIVATE
#define SUBPROCESS_PRIVATE
#define PROCESS_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
@ -18,7 +17,6 @@
#include "core/or/circuitbuild.h"
#include "app/config/statefile.h"
#include "test/test.h"
#include "lib/process/subprocess.h"
#include "lib/encoding/confline.h"
#include "lib/net/resolve.h"
#include "lib/process/process.h"

View file

@ -10,7 +10,7 @@
#define UTIL_PRIVATE
#define UTIL_MALLOC_PRIVATE
#define SOCKET_PRIVATE
#define SUBPROCESS_PRIVATE
#define PROCESS_WIN32_PRIVATE
#include "lib/testsupport/testsupport.h"
#include "core/or/or.h"
#include "lib/container/buffers.h"
@ -22,6 +22,7 @@
#include "test/test.h"
#include "lib/memarea/memarea.h"
#include "lib/process/waitpid.h"
#include "lib/process/process_win32.h"
#include "test/log_test_helpers.h"
#include "lib/compress/compress.h"
#include "lib/compress/compress_zstd.h"
@ -30,7 +31,6 @@
#include "lib/fs/winlib.h"
#include "lib/process/env.h"
#include "lib/process/pidfile.h"
#include "lib/process/subprocess.h"
#include "lib/intmath/weakrng.h"
#include "lib/thread/numcpus.h"
#include "lib/math/fp.h"
@ -4395,57 +4395,6 @@ test_util_format_dec_number(void *ptr)
return;
}
/**
* Test that we can properly format a Windows command line
*/
static void
test_util_join_win_cmdline(void *ptr)
{
/* Based on some test cases from "Parsing C++ Command-Line Arguments" in
* MSDN but we don't exercise all quoting rules because tor_join_win_cmdline
* will try to only generate simple cases for the child process to parse;
* i.e. we never embed quoted strings in arguments. */
const char *argvs[][4] = {
{"a", "bb", "CCC", NULL}, // Normal
{NULL, NULL, NULL, NULL}, // Empty argument list
{"", NULL, NULL, NULL}, // Empty argument
{"\"a", "b\"b", "CCC\"", NULL}, // Quotes
{"a\tbc", "dd dd", "E", NULL}, // Whitespace
{"a\\\\\\b", "de fg", "H", NULL}, // Backslashes
{"a\\\"b", "\\c", "D\\", NULL}, // Backslashes before quote
{"a\\\\b c", "d", "E", NULL}, // Backslashes not before quote
{ NULL } // Terminator
};
const char *cmdlines[] = {
"a bb CCC",
"",
"\"\"",
"\\\"a b\\\"b CCC\\\"",
"\"a\tbc\" \"dd dd\" E",
"a\\\\\\b \"de fg\" H",
"a\\\\\\\"b \\c D\\",
"\"a\\\\b c\" d E",
NULL // Terminator
};
int i;
char *joined_argv = NULL;
(void)ptr;
for (i=0; cmdlines[i]!=NULL; i++) {
log_info(LD_GENERAL, "Joining argvs[%d], expecting <%s>", i, cmdlines[i]);
joined_argv = tor_join_win_cmdline(argvs[i]);
tt_str_op(cmdlines[i],OP_EQ, joined_argv);
tor_free(joined_argv);
}
done:
tor_free(joined_argv);
}
#define MAX_SPLIT_LINE_COUNT 4
struct split_lines_test_t {
const char *orig_line; // Line to be split (may contain \0's)
@ -6226,7 +6175,6 @@ struct testcase_t util_tests[] = {
UTIL_TEST_WIN_ONLY(load_win_lib, 0),
UTIL_TEST(format_hex_number, 0),
UTIL_TEST(format_dec_number, 0),
UTIL_TEST(join_win_cmdline, 0),
UTIL_TEST(n_bits_set, 0),
UTIL_TEST(eat_whitespace, 0),
UTIL_TEST(sl_new_from_text_lines, 0),