From 2025597c0bc4fc1aa076af2476e0f8c4ce056168 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 5 May 2024 09:44:10 +0200 Subject: [PATCH] MDEV-21778 Disable system commands in mysql/mariadb client mysql --sandbox disables system (\!), tee (\T), pager with an argument(\P foo), source (\.) does *not* disable edit (\e). Use EDITOR=/bin/false to disable or, for example, EDITOR=rnano for something more useful does *not* disable pager (\P) without an argument. Use PAGER=cat or, for example PAGER=less LESSSECURE=1 for something more useful using a disabled command is an error, which can be ignored with --force Also, a "sandbox" command (\-) - enables the sandbox mode until EOF (current file or the session, if interactive) --- client/mysql.cc | 29 +++++++++++++++++++++++--- mysql-test/main/mysql.result | 24 ++++++++++++++++++++++ mysql-test/main/mysql.test | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 7ebb46a1a16..5c79dd7890b 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -136,7 +136,7 @@ typedef struct st_status ulong query_start_line; char *file_name; LINE_BUFFER *line_buff; - bool batch,add_to_history; + bool batch, add_to_history, sandbox; } STATUS; @@ -154,7 +154,7 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0, vertical=0, line_numbers=1, column_names=1,opt_html=0, opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 0, tty_password= 0, opt_nobeep=0, opt_reconnect=1, - opt_secure_auth= 0, + opt_secure_auth= 0, default_pager_set= 0, opt_sigint_ignore= 0, auto_vertical_output= 0, show_warnings= 0, executing_query= 0, @@ -235,7 +235,8 @@ static int com_quit(String *str,char*), com_rehash(String *str, char*), com_tee(String *str, char*), com_notee(String *str, char*), com_charset(String *str,char*), com_prompt(String *str, char*), com_delimiter(String *str, char*), - com_warnings(String *str, char*), com_nowarnings(String *str, char*); + com_warnings(String *str, char*), com_nowarnings(String *str, char*), + com_sandbox(String *str, char*); #ifdef USE_POPEN static int com_nopager(String *str, char*), com_pager(String *str, char*), @@ -311,6 +312,8 @@ static COMMANDS commands[] = { { "prompt", 'R', com_prompt, 1, "Change your mysql prompt."}, { "quit", 'q', com_quit, 0, "Quit mysql." }, { "rehash", '#', com_rehash, 0, "Rebuild completion hash." }, + { "sandbox", '-', com_sandbox, 0, + "Disallow commands that access the file system (except \\P without an argument and \\e)." }, { "source", '.', com_source, 1, "Execute an SQL script file. Takes a file name as an argument."}, { "status", 's', com_status, 0, "Get status information from the server."}, @@ -1675,6 +1678,8 @@ static struct my_option my_long_options[] = &safe_updates, &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.", &safe_updates, &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"sandbox", 0, "Disallow commands that access the file system (except \\P without an argument and \\e).", + &status.sandbox, &status.sandbox, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"secure-auth", 0, "Refuse client connecting to server if it" " uses old (pre-4.1.1) protocol.", &opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -4146,6 +4151,8 @@ static int com_tee(String *, char *line) { char file_name[FN_REFLEN], *end, *param; + if (status.sandbox) + return put_info("Not allowed in the sandbox mode", INFO_ERROR, 0); if (status.batch) return 0; while (my_isspace(charset_info, *line)) @@ -4226,6 +4233,8 @@ static int com_pager(String *, char *line) } else { + if (status.sandbox) + return put_info("Not allowed in the sandbox mode", INFO_ERROR, 0); end= strmake_buf(pager_name, param); while (end > pager_name && (my_isspace(charset_info,end[-1]) || my_iscntrl(charset_info,end[-1]))) @@ -4321,6 +4330,9 @@ static int com_shell(String *, char *line) { char *shell_cmd; + if (status.sandbox) + return put_info("Not allowed in the sandbox mode", INFO_ERROR, 0); + /* Skip space from line begin */ while (my_isspace(charset_info, *line)) line++; @@ -4416,6 +4428,9 @@ static int com_source(String *, char *line) FILE *sql_file; my_bool save_ignore_errors; + if (status.sandbox) + return put_info("Not allowed in the sandbox mode", INFO_ERROR, 0); + /* Skip space from file name */ while (my_isspace(charset_info,*line)) line++; @@ -4450,6 +4465,7 @@ static int com_source(String *, char *line) bfill((char*) &status,sizeof(status),(char) 0); status.batch=old_status.batch; // Run in batch mode + status.sandbox=old_status.sandbox; status.line_buff=line_buff; status.file_name=source_name; glob_buffer.length(0); // Empty command buffer @@ -4571,6 +4587,13 @@ static int com_use(String *, char *line) return 0; } +static int com_sandbox(String *, char *) +{ + status.sandbox= 1; + put_info("Sandbox mode.", INFO_INFO); + return 0; +} + static int com_warnings(String *, char *) { show_warnings = 1; diff --git a/mysql-test/main/mysql.result b/mysql-test/main/mysql.result index 48e0a9335ff..b168f1b57d5 100644 --- a/mysql-test/main/mysql.result +++ b/mysql-test/main/mysql.result @@ -633,3 +633,27 @@ drop table t1; WARNING: option '--enable-cleartext-plugin' is obsolete. 1 1 +# End of 10.3 tests +# +# MDEV-21778 Disable system commands in mysql/mariadb client +# +ERROR at line 1: Not allowed in the sandbox mode +1 +ERROR at line 1: Not allowed in the sandbox mode +2 +ERROR at line 1: Not allowed in the sandbox mode +3 +1 +entering sandbox +system +tee +source +^^^ +2 +entering sandbox +system +tee +source +^^^ +3 +# End of 10.5 tests diff --git a/mysql-test/main/mysql.test b/mysql-test/main/mysql.test index 0f41add821a..d71c0b59575 100644 --- a/mysql-test/main/mysql.test +++ b/mysql-test/main/mysql.test @@ -716,3 +716,43 @@ drop table t1; # --echo --exec $MYSQL test --enable-cleartext-plugin -e "select 1" + +--echo # End of 10.3 tests + +--echo # +--echo # MDEV-21778 Disable system commands in mysql/mariadb client +--echo # + +--error 1 +--exec $MYSQL --sandbox -Ne "select 1; \! echo foo; select 0" 2>&1 +--error 1 +--exec $MYSQL --sandbox -Ne "select 2; \T echo foo; select 0" 2>&1 +--error 1 +--exec $MYSQL --sandbox -Ne "select 3; \. echo.foo; select 0" 2>&1 + +--write_file $MYSQL_TMP_DIR/mysql_in +select 'entering sandbox'; +\- +select 'system'; +\! echo foo +select 'tee'; +\T echo foo +select 'source'; +\. echo.foo +select '^^^'; +EOF + +write_line "select 1; +source $MYSQL_TMP_DIR/mysql_in; +select 2; +source $MYSQL_TMP_DIR/mysql_in; +sandbox; +select 3; +source $MYSQL_TMP_DIR/mysql_in;" $MYSQL_TMP_DIR/mysql_in2; + +--exec $MYSQL -fN <$MYSQL_TMP_DIR/mysql_in2 + +--remove_file $MYSQL_TMP_DIR/mysql_in +--remove_file $MYSQL_TMP_DIR/mysql_in2 + +--echo # End of 10.5 tests