improve bash history importing

Reject more invalid commands from the bash history file.

Fixes #3636

(cherry picked from commit 6c4a51d56e)
This commit is contained in:
Kurtis Rader 2017-05-20 21:03:31 -07:00 committed by David Adam
parent 44830589ab
commit 06ea31d0ab
3 changed files with 33 additions and 13 deletions

View File

@ -3139,8 +3139,13 @@ void history_tests_t::test_history_formats(void) {
} else {
// The results are in the reverse order that they appear in the bash history file.
// We don't expect whitespace to be elided.
const wchar_t *expected[] = {L"sleep 123", L" final line", L"echo supsup",
L"history --help", L"echo foo", NULL};
const wchar_t *expected[] = {L"sleep 123",
L" final line",
L"echo supsup",
L"export XVAR='exported'",
L"history --help",
L"echo foo",
NULL};
history_t &test_history = history_t::history_with_name(L"bash_import");
test_history.populate_from_bash(f);
if (!history_equals(test_history, expected)) {

View File

@ -36,6 +36,7 @@
#include "lru.h"
#include "parse_constants.h"
#include "parse_tree.h"
#include "parse_util.h"
#include "path.h"
#include "reader.h"
#include "signal.h"
@ -1677,21 +1678,30 @@ void history_t::populate_from_config_path() {
static bool should_import_bash_history_line(const std::string &line) {
if (line.empty()) return false;
// Very naive tests! Skip `export` and comments.
// TODO: We should probably should skip other commands.
const char *const ignore_prefixes[] = {"export ", "#"};
parse_node_tree_t parse_tree;
wcstring wide_line = str2wcstring(line);
if (!parse_tree_from_string(wide_line, parse_flag_none, &parse_tree, NULL)) return false;
for (size_t i = 0; i < sizeof ignore_prefixes / sizeof *ignore_prefixes; i++) {
const char *prefix = ignore_prefixes[i];
if (!line.compare(0, strlen(prefix), prefix)) {
return false;
}
}
// In doing this test do not allow incomplete strings. Hence the "false" argument.
parse_error_list_t errors;
parse_util_detect_errors(wide_line, &errors, false);
if (!errors.empty()) return false;
// The following are Very naive tests!
// Skip comments.
if (line[0] == '#') return false;
// Skip lines with backticks.
if (line.find('`') != std::string::npos) return false;
// Skip lines that end with a backslash since we do not handle multiline commands from bash.
// Skip lines with [[...]] and ((...)) since we don't handle those constructs.
if (line.find("[[") != std::string::npos) return false;
if (line.find("]]") != std::string::npos) return false;
if (line.find("((") != std::string::npos) return false;
if (line.find("))") != std::string::npos) return false;
// Skip lines that end with a backslash. We do not handle multiline commands from bash history.
if (line.back() == '\\') return false;
return true;

View File

@ -1,7 +1,7 @@
echo foo
history --help
#1339718290
export HISTTIMEFORMAT='%F %T '
export XVAR='exported'
#1339718298
echo supsup
#abcde
@ -11,4 +11,9 @@ echo hello \
final line
another `command
and arg` to skip
backticks `are not allowed`
a && echo invalid construct
[[ x = y ]] && echo double brackets not allowed
(( 1 = 2 )) && echo double parens not allowed
posix_cmd_sub $(is not supported)
sleep 123