Skip to content

Commit

Permalink
yaco: fix crash when starting yaco on invalid git repositories
Browse files Browse the repository at this point in the history
  • Loading branch information
bamiaux committed Jul 6, 2018
1 parent 7f30e65 commit ac35513
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 37 deletions.
3 changes: 3 additions & 0 deletions YaCo/yaco_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ def init(self, *args, **kwargs):
if input_filename.count("_local.") > 0 and os.path.exists(".git"):
print("yaco: initializing")
start()
if not yaco.is_started():
return idaapi.PLUGIN_SKIP

return idaapi.PLUGIN_KEEP

if "_local." not in input_filename and os.path.exists(".git"):
Expand Down
27 changes: 16 additions & 11 deletions YaLibs/YaToolsIDALib/Repository.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,15 @@ namespace

// IRepository
std::string get_cache() override;
void add_comment(const std::string& msg) override;
void check_valid_cache_startup() override; // can stop IDA
void add_comment(const std::string& msg) override;
bool check_valid_cache_startup() override; // can stop IDA
std::string update_cache() override;
bool commit_cache() override;
void toggle_repo_auto_sync() override;
void sync_and_push_original_idb() override;
void discard_and_pull_idb() override;
void diff_index(const std::string& from, const on_blob_fn& on_blob) const override;
bool idb_is_tracked();
bool commit_cache() override;
void toggle_repo_auto_sync() override;
void sync_and_push_original_idb() override;
void discard_and_pull_idb() override;
void diff_index(const std::string& from, const on_blob_fn& on_blob) const override;
bool idb_is_tracked();

// Retrieve informations with IDA GUI
void ask_to_checkout_modified_files();
Expand Down Expand Up @@ -260,6 +260,9 @@ Repository::Repository(const std::string& path)
const bool repo_already_exists = is_git_working_dir(path);

git_ = MakeGit(path);
if(!git_)
return;

if (!ensure_git_globals())
LOG(ERROR, "Unable to ensure git globals\n");

Expand Down Expand Up @@ -305,9 +308,11 @@ void Repository::add_comment(const std::string& msg)
comments_.emplace_back(msg);
}

void Repository::check_valid_cache_startup()
bool Repository::check_valid_cache_startup()
{
LOG(DEBUG, "Validating cache...\n");
if(!git_)
return false;

if (has_remote("origin"))
{
Expand All @@ -330,7 +335,7 @@ void Repository::check_valid_cache_startup()
if (std::regex_match(idb_prefix, std::regex(".*_local$")))
{
LOG(DEBUG, "Cache validated\n");
return;
return true;
}

LOG(INFO, "Current IDB filename is missing _local suffix\n");
Expand All @@ -343,7 +348,7 @@ void Repository::check_valid_cache_startup()
if (ec)
{
LOG(ERROR, "Unable to create local idb file, error: %s\n", ec.message().c_str());
return;
return false;
}
}

Expand Down
28 changes: 10 additions & 18 deletions YaLibs/YaToolsIDALib/Repository.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,18 @@ struct IRepository
{
virtual ~IRepository() = default;

virtual std::string get_cache() = 0;

virtual void add_comment(const std::string& msg) = 0;

virtual void check_valid_cache_startup() = 0;
using on_blob_fn = std::function<int(const char*, bool, const void*, size_t)>;

virtual std::string get_cache() = 0;
virtual void add_comment(const std::string& msg) = 0;
virtual bool check_valid_cache_startup() = 0;
virtual std::string update_cache() = 0;

virtual bool commit_cache() = 0;

virtual void toggle_repo_auto_sync() = 0;

virtual void sync_and_push_original_idb() = 0;

virtual void discard_and_pull_idb() = 0;

typedef std::function<int(const char*, bool, const void*, size_t)> on_blob_fn;
virtual void diff_index(const std::string& from, const on_blob_fn& on_blob) const = 0;

virtual bool idb_is_tracked() = 0;
virtual bool commit_cache() = 0;
virtual void toggle_repo_auto_sync() = 0;
virtual void sync_and_push_original_idb() = 0;
virtual void discard_and_pull_idb() = 0;
virtual void diff_index(const std::string& from, const on_blob_fn& on_blob) const = 0;
virtual bool idb_is_tracked() = 0;
};

std::shared_ptr<IRepository> MakeRepository(const std::string& path);
19 changes: 14 additions & 5 deletions YaLibs/YaToolsIDALib/YaCo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ namespace
std::shared_ptr<IRepository> repo_;
std::shared_ptr<IEvents> events_;
std::shared_ptr<IHooks> hooks_;

std::vector<action_desc_t> action_descs_;
bool loaded_;
};
}

Expand All @@ -118,10 +118,13 @@ YaCo::YaCo()
: repo_(MakeRepository("."))
, events_(MakeEvents(*repo_))
, hooks_(MakeHooks(*events_))
, loaded_(false)
{
LOG(INFO, "YaCo version %s\n", GitVersion);

repo_->check_valid_cache_startup();
if(!repo_->check_valid_cache_startup())
{
LOG(ERROR, "unable to start\n");
return;
}

// hooks not hooked yet
initial_load();
Expand All @@ -144,6 +147,7 @@ YaCo::YaCo()
}

hooks_->hook();
loaded_ = true;
}

void YaCo::export_database()
Expand Down Expand Up @@ -262,5 +266,10 @@ std::shared_ptr<IYaCo> MakeYaCo()
{
msg("%s", &message[prefix + 1]);
});
return std::make_shared<YaCo>();
LOG(INFO, "YaCo version %s\n", GitVersion);
const auto ptr = std::make_shared<YaCo>();
if(!ptr->loaded_)
return std::nullptr_t();

return ptr;
}
7 changes: 4 additions & 3 deletions YaLibs/YaToolsLib/Git.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ namespace
#define FAIL_WITH(X, FMT, ...) do\
{\
const auto giterr = giterr_last();\
LOG(ERROR, "%s: " FMT, giterr ? giterr->message : "", ## __VA_ARGS__);\
LOG(ERROR, "%s: " FMT "\n", giterr ? giterr->message : "", ## __VA_ARGS__);\
return (X);\
} while(0)

Expand All @@ -140,10 +140,11 @@ namespace

std::shared_ptr<IGit> init(const std::string& path, Git::ECloneMode emode)
{
const auto fullpath = fs::canonical(fs::absolute(path));
git_repository* ptr_repo = nullptr;
auto err = git_repository_init(&ptr_repo, path.data(), emode == Git::CLONE_BARE);
auto err = git_repository_init(&ptr_repo, fullpath.generic_string().data(), emode == Git::CLONE_BARE);
if(err != GIT_OK)
FAIL_WITH(std::nullptr_t(), "unable to initialize %srepository at %s", emode == Git::CLONE_BARE ? "bare " : "", path.data());
FAIL_WITH(std::nullptr_t(), "unable to initialize %srepository at %s", emode == Git::CLONE_BARE ? "bare " : "", fullpath.generic_string().data());

auto repo = make_unique(ptr_repo);
return std::make_shared<Git>(path, std::move(repo));
Expand Down
5 changes: 5 additions & 0 deletions YaLibs/YaToolsPy/YaSwig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ namespace yaswig
return {::MakeYaCo()};
}

bool Private::is_started()
{
return !!yaco;
}

void Private::sync_and_push_idb()
{
yaco->sync_and_push_idb(IDA_NOT_INTERACTIVE);
Expand Down
1 change: 1 addition & 0 deletions YaLibs/YaToolsPy/YaSwig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace yaswig
{
std::shared_ptr<IYaCo> yaco;

bool is_started();
void sync_and_push_idb();
void discard_and_pull_idb();
};
Expand Down
39 changes: 39 additions & 0 deletions tests/tests/test_git.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/python

# Copyright (C) 2017 The YaCo Authors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.


import runtests
import unittest
import os
import tempfile
import shutil


class Fixture(runtests.Fixture):

def test_invalid_git(self):
a, b = self.setup_repos()

# remove git directory & replace it with a file
os.rename(os.path.join(a.path, ".git"), os.path.join(a.path, ".git.old"))
with open(os.path.join(a.path, ".git"), "wb") as fh:
fh.write("nothing")

# start yaco again and expect no crashes
a.run(
self.script("idc.AddEnum(-1, 'name', idaapi.hexflag())"),
)

0 comments on commit ac35513

Please sign in to comment.