Compare commits
7 次程式碼提交
feature/ma
...
8d685dc581
作者 | SHA1 | 提交日期 | |
---|---|---|---|
8d685dc581 | |||
ed43f5f700 | |||
10f00aeb45 | |||
67eb8b6428 | |||
f26fd19fb4 | |||
204a72da1f | |||
88816a4015 |
2
Makefile
2
Makefile
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra
|
CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra
|
||||||
RELEASE_CXXFLAGS=-std=c++17 -O3 -pipe -MMD -Wall -Wextra
|
RELEASE_CXXFLAGS=-std=c++17 -O3 -pipe -MMD -Wall -Wextra
|
||||||
LDFLAGS=-lsqlite3 -lpthread -lcrypto -lstdc++fs -lseccomp
|
LDFLAGS=-lsqlite3 -lpthread -lcrypto -lstdc++fs
|
||||||
INCLUDEFLAGS=-I submodules/sqlitemoderncpp/hdr -I submodules/cpp-httplib -I submodules/qssb.h
|
INCLUDEFLAGS=-I submodules/sqlitemoderncpp/hdr -I submodules/cpp-httplib -I submodules/qssb.h
|
||||||
|
|
||||||
CXX=g++
|
CXX=g++
|
||||||
|
14
qswiki.cpp
14
qswiki.cpp
@ -77,21 +77,21 @@ int main(int argc, char **argv)
|
|||||||
Logger::error() << "Sandbox is not supported, exiting";
|
Logger::error() << "Sandbox is not supported, exiting";
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
if(argc < 2)
|
||||||
|
{
|
||||||
|
std::cerr << "no path to config file provided" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
std::string configpath = std::filesystem::absolute(argv[1]).string();
|
||||||
if(!sandbox->enableForInit())
|
if(!sandbox->enableForInit())
|
||||||
{
|
{
|
||||||
Logger::error() << "Sandboxing for init mode could not be activated.";
|
Logger::error() << "Sandboxing for init mode could not be activated.";
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(argc < 2)
|
|
||||||
{
|
|
||||||
std::cerr << "no path to config file provided" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ConfigReader configreader(argv[1]);
|
ConfigReader configreader(configpath);
|
||||||
Config config = configreader.readConfig();
|
Config config = configreader.readConfig();
|
||||||
|
|
||||||
// TODO: config.connectiontring only works as long as we only support sqlite of course
|
// TODO: config.connectiontring only works as long as we only support sqlite of course
|
||||||
|
@ -26,16 +26,26 @@
|
|||||||
bool SandboxLinux::enableForInit()
|
bool SandboxLinux::enableForInit()
|
||||||
{
|
{
|
||||||
umask(0027);
|
umask(0027);
|
||||||
struct qssb_policy policy = {0};
|
struct qssb_policy *policy = qssb_init_policy();
|
||||||
int blacklisted_syscalls[] = {QSSB_SYS(execveat), QSSB_SYS(execve), -1};
|
if(policy == NULL)
|
||||||
policy.blacklisted_syscalls = blacklisted_syscalls;
|
|
||||||
policy.no_new_privs = 1;
|
|
||||||
int result = qssb_enable_policy(&policy);
|
|
||||||
if(result != 0)
|
|
||||||
{
|
{
|
||||||
Logger::error() << "Failed to install sandboxing policy (init): " << result;
|
Logger::error() << "Failed to init sandboxing policy (init)";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
policy->namespace_options = QSSB_UNSHARE_USER;
|
||||||
|
policy->drop_caps = 0;
|
||||||
|
qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execveat));
|
||||||
|
qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execve));
|
||||||
|
qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
|
||||||
|
|
||||||
|
int result = qssb_enable_policy(policy);
|
||||||
|
if(result != 0)
|
||||||
|
{
|
||||||
|
Logger::error() << "Failed to enable sandboxing policy (init): " << result;
|
||||||
|
qssb_free_policy(policy);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qssb_free_policy(policy);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,28 +54,34 @@ bool SandboxLinux::enablePreWorker(std::vector<std::string> fsPaths)
|
|||||||
std::sort(fsPaths.begin(), fsPaths.end(),
|
std::sort(fsPaths.begin(), fsPaths.end(),
|
||||||
[](const std::string &a, const std::string &b) { return a.length() < b.length(); });
|
[](const std::string &a, const std::string &b) { return a.length() < b.length(); });
|
||||||
|
|
||||||
struct qssb_path_policy *policies = new qssb_path_policy[fsPaths.size()];
|
struct qssb_policy *policy = qssb_init_policy();
|
||||||
|
if(policy == NULL)
|
||||||
|
{
|
||||||
|
Logger::error() << "Failed to init sandboxing policy (pre)";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for(unsigned int i = 0; i < fsPaths.size(); i++)
|
for(unsigned int i = 0; i < fsPaths.size(); i++)
|
||||||
{
|
{
|
||||||
policies[i].next = policies + (i + 1);
|
qssb_append_path_policy(policy, QSSB_FS_ALLOW_READ | QSSB_FS_ALLOW_WRITE, fsPaths[i].c_str());
|
||||||
policies[i].mountpoint = fsPaths[i].c_str();
|
|
||||||
policies[i].policy = QSSB_MOUNT_ALLOW_READ | QSSB_MOUNT_ALLOW_WRITE;
|
|
||||||
}
|
}
|
||||||
policies[fsPaths.size() - 1].next = NULL;
|
|
||||||
|
|
||||||
struct qssb_policy policy = {0};
|
policy->namespace_options = QSSB_UNSHARE_MOUNT;
|
||||||
policy.path_policies = policies;
|
policy->drop_caps = 0;
|
||||||
policy.namespace_options |= QSSB_UNSHARE_MOUNT;
|
policy->mount_path_policies_to_chroot = 1;
|
||||||
policy.namespace_options |= QSSB_UNSHARE_USER;
|
|
||||||
int blacklisted_syscalls[] = {QSSB_SYS(execveat), QSSB_SYS(execve), -1};
|
qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execveat));
|
||||||
policy.blacklisted_syscalls = blacklisted_syscalls;
|
qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execve));
|
||||||
int result = qssb_enable_policy(&policy);
|
qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
|
||||||
|
|
||||||
|
int result = qssb_enable_policy(policy);
|
||||||
if(result != 0)
|
if(result != 0)
|
||||||
{
|
{
|
||||||
Logger::error() << "Failed to install sandboxing policy (preworker): %i" << result;
|
Logger::error() << "Failed to install sandboxing policy (preworker): %i" << result;
|
||||||
|
qssb_free_policy(policy);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delete[] policies;
|
qssb_free_policy(policy);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,30 +104,35 @@ bool SandboxLinux::supported()
|
|||||||
}
|
}
|
||||||
bool SandboxLinux::enableForWorker()
|
bool SandboxLinux::enableForWorker()
|
||||||
{
|
{
|
||||||
struct qssb_policy policy = {0};
|
struct qssb_policy *policy = qssb_init_policy();
|
||||||
policy.drop_caps = 1;
|
if(policy == NULL)
|
||||||
policy.not_dumpable = 1;
|
{
|
||||||
policy.no_new_privs = 1;
|
Logger::error() << "Failed to init sandboxing policy (worker) ";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
policy->drop_caps = 1;
|
||||||
|
policy->not_dumpable = 1;
|
||||||
|
policy->no_new_privs = 1;
|
||||||
|
policy->namespace_options = 0;
|
||||||
|
|
||||||
/* TODO: as said, a whitelist approach is better. As such, this list is bound to be incomplete in the
|
/* TODO: as said, a whitelist approach is better. As such, this list is bound to be incomplete in the
|
||||||
* sense that more could be listed here and some critical ones are probably missing */
|
* sense that more could be listed here and some critical ones are probably missing */
|
||||||
int blacklisted_syscalls[] = {QSSB_SYS(setuid),
|
|
||||||
QSSB_SYS(connect),
|
/* TODO: use qssb groups */
|
||||||
QSSB_SYS(chroot),
|
long blacklisted_syscalls[] = {QSSB_SYS(setuid), QSSB_SYS(connect), QSSB_SYS(chroot), QSSB_SYS(pivot_root),
|
||||||
QSSB_SYS(pivot_root),
|
QSSB_SYS(mount), QSSB_SYS(setns), QSSB_SYS(unshare), QSSB_SYS(ptrace),
|
||||||
QSSB_SYS(mount),
|
QSSB_SYS(personality), QSSB_SYS(prctl)};
|
||||||
QSSB_SYS(setns),
|
|
||||||
QSSB_SYS(unshare),
|
qssb_append_syscalls_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, blacklisted_syscalls,
|
||||||
QSSB_SYS(ptrace),
|
sizeof(blacklisted_syscalls) / sizeof(blacklisted_syscalls[0]));
|
||||||
QSSB_SYS(personality),
|
qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
|
||||||
QSSB_SYS(prctl),
|
|
||||||
-1};
|
if(qssb_enable_policy(policy) != 0)
|
||||||
policy.blacklisted_syscalls = blacklisted_syscalls;
|
|
||||||
if(qssb_enable_policy(&policy) != 0)
|
|
||||||
{
|
{
|
||||||
Logger::error() << "Sandbox: Activation of seccomp blacklist failed!";
|
Logger::error() << "Sandbox: Activation of seccomp blacklist failed!";
|
||||||
|
qssb_free_policy(policy);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
qssb_free_policy(policy);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -25,24 +25,13 @@ count integer
|
|||||||
CREATE TABLE category(id INTEGER PRIMARY KEY, name varchar(255));
|
CREATE TABLE category(id INTEGER PRIMARY KEY, name varchar(255));
|
||||||
CREATE TABLE categorymember(id INTEGER PRIMARY KEY, category REFERENCES category(id), page REFERENCES page (id));
|
CREATE TABLE categorymember(id INTEGER PRIMARY KEY, category REFERENCES category(id), page REFERENCES page (id));
|
||||||
CREATE INDEX revisionid ON revision (revisionid DESC);
|
CREATE INDEX revisionid ON revision (revisionid DESC);
|
||||||
CREATE INDEX pagename ON page (name)
|
CREATE INDEX pagename ON page (name);
|
||||||
;
|
CREATE INDEX token ON session (token);
|
||||||
CREATE INDEX token ON session (token)
|
CREATE VIRTUAL TABLE search USING fts5(content, page UNINDEXED, content=revision,content_rowid=id);
|
||||||
;
|
|
||||||
CREATE TRIGGER search_ai AFTER INSERT ON revision BEGIN
|
|
||||||
DELETE FROM search WHERE page = new.page;
|
|
||||||
INSERT INTO search(rowid, content, page) VALUES (new.id, new.content, new.page);
|
|
||||||
END;
|
|
||||||
CREATE TRIGGER search_au AFTER UPDATE ON revision BEGIN
|
|
||||||
DELETE FROM search WHERE page = old.page;
|
|
||||||
INSERT INTO search(rowid, content, page) VALUES (new.id, new.content, new.page);
|
|
||||||
END;
|
|
||||||
CREATE VIRTUAL TABLE search USING fts5(content, page UNINDEXED, content=revision,content_rowid=id)
|
|
||||||
/* search(content,page) */;
|
|
||||||
CREATE TABLE IF NOT EXISTS 'search_data'(id INTEGER PRIMARY KEY, block BLOB);
|
|
||||||
CREATE TABLE IF NOT EXISTS 'search_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
|
|
||||||
CREATE TABLE IF NOT EXISTS 'search_docsize'(id INTEGER PRIMARY KEY, sz BLOB);
|
|
||||||
CREATE TABLE IF NOT EXISTS 'search_config'(k PRIMARY KEY, v) WITHOUT ROWID;
|
|
||||||
CREATE TRIGGER search_ad AFTER DELETE ON revision BEGIN
|
CREATE TRIGGER search_ad AFTER DELETE ON revision BEGIN
|
||||||
INSERT INTO search(search, rowid, content, page) VALUES('delete', old.id, old.content, old.page);
|
INSERT INTO search(search, rowid, content, page) VALUES('delete', old.id, old.content, old.page);
|
||||||
END;
|
END;
|
||||||
|
CREATE TRIGGER search_ai AFTER INSERT ON revision BEGIN
|
||||||
|
INSERT INTO search(search, rowid, content, page) SELECT 'delete', id, content, page FROM revision WHERE page = new.page AND revisionid = new.revisionid - 1;
|
||||||
|
INSERT INTO search(rowid, content, page) VALUES (new.id, new.content, new.page);
|
||||||
|
END;
|
||||||
|
Submodule submodules/cpp-httplib updated: 63643e6386...d87d0672a8
Submodule submodules/qssb.h updated: 9df2e9ee90...11d64c6fcf
@ -46,6 +46,12 @@ std::string utils::html_xss(std::string_view str)
|
|||||||
case '%':
|
case '%':
|
||||||
result += "%";
|
result += "%";
|
||||||
break;
|
break;
|
||||||
|
case '\'':
|
||||||
|
result += "'";
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
result += "&";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
result += c;
|
result += c;
|
||||||
}
|
}
|
||||||
@ -93,7 +99,7 @@ std::vector<std::string> utils::split(const std::string &str, char delim)
|
|||||||
// TODO: can easily break if we pass a regex here
|
// TODO: can easily break if we pass a regex here
|
||||||
std::vector<std::string> utils::split(const std::string &str, const std::string &delim)
|
std::vector<std::string> utils::split(const std::string &str, const std::string &delim)
|
||||||
{
|
{
|
||||||
std::regex regex { delim + "+" };
|
std::regex regex{delim + "+"};
|
||||||
return split(str, regex);
|
return split(str, regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user