#include #include #include #include #include //std bind #include // signal #include #include //unshare #include //getpid #include // umount #include #include #include #include #include using json = nlohmann::json; #include "bot.h" static bool run = true; void sig_handler(int sig_num) { Log::info << "signalHandler triggered"; run = false; (void) sig_num; } class CommandStart : public TelegramAPI::Command { public: CommandStart() : TelegramAPI::Command("/start") {} virtual bool process(TelegramAPI::Manager* m, const TelegramAPI::Message& msg) { TelegramAPI::InlineKeyboard kb; kb.addButton(TelegramAPI::InlineButton::createSwitchInlineQuery("Open in Chat"), 0); return m->sendMessage(msg.chat.id, "This bot is inline only.", kb); } }; static bool enableSecurity() { // create new mount and user namespace if(unshare(CLONE_NEWUSER|CLONE_NEWNS) == -1) { Log::warn << "unsahre(NEWUSER|NEWNS) failed: " << strerror(errno); } Log::info << "new userid: " << getuid(); // chroot in current directory if(chroot("./") == -1) { Log::fatal << "chroot failed " << strerror(errno); return false; } //setup seccomp scmp_filter_ctx scmp = seccomp_init(SCMP_ACT_KILL_PROCESS); if(!scmp) { Log::fatal << "init seccmp failed"; return false; } seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(poll), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(openat), 1, SCMP_A2_64(SCMP_CMP_MASKED_EQ, ~ (O_RDONLY | O_NONBLOCK | O_CLOEXEC), 0)); // datein nur readonly und ggf nonblock öffnen seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(stat), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(writev), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(readv), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(pwritev), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(preadv), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(pwritev2), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(preadv2), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(restart_syscall), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(socketpair), 0); // what? seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(get_robust_list), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(sendmmsg), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(uname), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(clone), 0); // curl wants to spawn threads seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0); //apply seccomp int err = seccomp_load(scmp); if(err != 0) { seccomp_release(scmp); Log::fatal << "could not load seccomp " << strerror(err); return false; } seccomp_release(scmp); /* //drop all capabilities and apply nobody uid const uid_t nobody = 65534; const gid_t groups[] = {65534}; if (cap_setgroups(groups[0], 1, groups) != 0) { Log::fatal << "cap_setgroups() failed: " << strerror(errno); return false; } if (cap_setuid(nobody) != 0) { Log::fatal << "cap_setuid() failed: " << strerror(errno); return false; } if(cap_set_mode(CAP_MODE_NOPRIV) != 0) { Log::fatal << "cap_set_mode(CAP_MODE_NOPRIV) failed: " << strerror(errno); return false; } */ return true; } int main(int argc, const char** argv) { Log::init(); Log::setConsoleLogLevel(Log::Level::TRACE); Log::addLogfile("log.txt", Log::Level::WARN); #if __unix__ Log::setColoredOutput(true); #endif Log::info << "Hello, World! pid: " << getpid() << " userid: " << getuid(); //read config std::ifstream configfile("config.json"); json j; configfile >> j; FontBot bot; TelegramAPI::Manager tapi(j["telegram"]["apikey"]); if(!enableSecurity()) return 1; // test seccomp settings // Log::info << "try to open this file"; // int fd = open(argv[0], O_WRONLY); // Log::fatal << "ok"; std::unique_ptr cmd(new CommandStart()); tapi.registerCommand(std::move(cmd)); namespace pl = std::placeholders; tapi.setInlineQueryHandler(std::bind(&FontBot::handleInline, &bot, pl::_1, pl::_2)); signal(SIGINT, sig_handler); while(run) { tapi.getUpdates(); } Log::stop(); return 0; }