common/Protocol.hpp | 15 ++++ common/Seccomp.cpp | 89 +++++++++++++++++++++++++++-- common/Seccomp.hpp | 4 + kit/ForKit.cpp | 28 +++++++++ kit/Kit.cpp | 33 ++++++++++ loleaflet/admin.strings.js | 4 + loleaflet/dist/admin/adminSettings.html | 8 ++ loleaflet/src/admin/AdminSocketSettings.js | 4 + loolwsd.xml.in | 4 + wsd/Admin.cpp | 78 +++++++++++++++++++------ wsd/Admin.hpp | 15 ++++ wsd/AdminModel.hpp | 14 ++++ wsd/LOOLWSD.cpp | 39 ++++++++++-- wsd/LOOLWSD.hpp | 2 14 files changed, 307 insertions(+), 30 deletions(-)
New commits: commit 459249b17759d5f15fe17b96bdd7897b0c8b47ba Author: Ashod Nakashian <[email protected]> Date: Sun Jun 11 23:47:48 2017 -0400 wsd: apply rlimits set from Admin Console to ForKit Change-Id: I425c28ce08c5ecd659c4fe8eaa1a7ed3634e7f18 Reviewed-on: https://gerrit.libreoffice.org/38678 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp index 0fc64aaa..ca1bc950 100644 --- a/wsd/Admin.cpp +++ b/wsd/Admin.cpp @@ -331,6 +331,7 @@ Admin::Admin() : SocketPoll("admin"), _model(AdminModel()), _forKitPid(-1), + _forKitWritePipe(-1), _lastTotalMemory(0), _lastJiffies(0), _memStatsTaskIntervalMs(5000), @@ -497,6 +498,16 @@ void Admin::addBytes(const std::string& docKey, uint64_t sent, uint64_t recv) { _model.addBytes(docKey, sent, recv); }); } +void Admin::notifyForkit() +{ + std::ostringstream oss; + oss << "setconfig limit_virt_mem_mb " << _defDocProcSettings.LimitVirtMemMb << '\n' + << "setconfig limit_data_mem_kb " << _defDocProcSettings.LimitDataMemKb << '\n' + << "setconfig limit_stack_mem_kb " << _defDocProcSettings.LimitStackMemKb << '\n' + << "setconfig limit_file_size_mb " << _defDocProcSettings.LimitFileSizeMb << '\n'; + IoUtil::writeToPipe(_forKitWritePipe, oss.str()); +} + void Admin::dumpState(std::ostream& os) { // FIXME: be more helpful ... diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp index 4faa3df2..5ca87572 100644 --- a/wsd/Admin.hpp +++ b/wsd/Admin.hpp @@ -86,6 +86,7 @@ public: void rmDoc(const std::string& docKey); void setForKitPid(const int forKitPid) { _forKitPid = forKitPid; } + void setForKitWritePipe(const int forKitWritePipe) { _forKitWritePipe = forKitWritePipe; } /// Callers must ensure that modelMutex is acquired AdminModel& getModel(); @@ -105,13 +106,22 @@ public: void dumpState(std::ostream& os) override; const DocProcSettings& getDefDocProcSettings() const { return _defDocProcSettings; } - void setDefDocProcSettings(const DocProcSettings& docProcSettings) { _defDocProcSettings = docProcSettings; } + void setDefDocProcSettings(const DocProcSettings& docProcSettings) + { + _defDocProcSettings = docProcSettings; + notifyForkit(); + } + +private: + /// Notify Forkit of changed settings. + void notifyForkit(); private: /// The model is accessed only during startup & in /// the Admin Poll thread. AdminModel _model; int _forKitPid; + int _forKitWritePipe; size_t _lastTotalMemory; size_t _lastJiffies; diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index bdc10893..0aead10a 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -807,6 +807,13 @@ void LOOLWSD::initialize(Application& self) ServerApplication::initialize(self); + DocProcSettings docProcSettings; + docProcSettings.LimitVirtMemMb = getConfigValue<int>("per_document.limit_virt_mem_mb", 0); + docProcSettings.LimitDataMemKb = getConfigValue<int>("per_document.limit_data_mem_kb", 0); + docProcSettings.LimitStackMemKb = getConfigValue<int>("per_document.limit_stack_mem_kb", 0); + docProcSettings.LimitFileSizeMb = getConfigValue<int>("per_document.limit_file_size_mb", 0); + Admin::instance().setDefDocProcSettings(docProcSettings); + #if ENABLE_DEBUG std::cerr << "\nLaunch this in your browser:\n\n" << getLaunchURI() << '\n' << std::endl; @@ -1163,13 +1170,7 @@ bool LOOLWSD::createForKit() args.push_back("--clientport=" + std::to_string(ClientPortNumber)); args.push_back("--masterport=" + std::to_string(MasterPortNumber)); - DocProcSettings docProcSettings; - docProcSettings.LimitVirtMemMb = getConfigValue<int>("per_document.limit_virt_mem_mb", 0); - docProcSettings.LimitDataMemKb = getConfigValue<int>("per_document.limit_data_mem_kb", 0); - docProcSettings.LimitStackMemKb = getConfigValue<int>("per_document.limit_stack_mem_kb", 0); - docProcSettings.LimitFileSizeMb = getConfigValue<int>("per_document.limit_file_size_mb", 0); - Admin::instance().setDefDocProcSettings(docProcSettings); - + const DocProcSettings& docProcSettings = Admin::instance().getDefDocProcSettings(); std::ostringstream ossRLimits; ossRLimits << "limit_virt_mem_mb:" << docProcSettings.LimitVirtMemMb; ossRLimits << ";limit_data_mem_kb:" << docProcSettings.LimitDataMemKb; @@ -1199,14 +1200,20 @@ bool LOOLWSD::createForKit() std::unique_lock<std::mutex> newChildrenLock(NewChildrenMutex); // Always reap first, in case we haven't done so yet. - int status; - waitpid(ForKitProcId, &status, WUNTRACED | WNOHANG); - ForKitProcId = -1; - Admin::instance().setForKitPid(ForKitProcId); + if (ForKitProcId != -1) + { + int status; + waitpid(ForKitProcId, &status, WUNTRACED | WNOHANG); + ForKitProcId = -1; + Admin::instance().setForKitPid(ForKitProcId); + } if (ForKitWritePipe != -1) + { close(ForKitWritePipe); - ForKitWritePipe = -1; + ForKitWritePipe = -1; + Admin::instance().setForKitWritePipe(ForKitWritePipe); + } // ForKit always spawns one. ++OutstandingForks; @@ -1227,6 +1234,7 @@ bool LOOLWSD::createForKit() // Init the Admin manager Admin::instance().setForKitPid(ForKitProcId); + Admin::instance().setForKitWritePipe(ForKitWritePipe); return ForKitProcId != -1; #endif commit 9e11cd7db711b86fadbc0a2d00920268779233d2 Author: Ashod Nakashian <[email protected]> Date: Sun Jun 11 22:51:38 2017 -0400 Support setting rlimits from Admin Console Change-Id: Ia0d45948998d7a5612a1828a90ad20908d07639e Reviewed-on: https://gerrit.libreoffice.org/38677 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/loleaflet/admin.strings.js b/loleaflet/admin.strings.js index 9bc38b29..0850a61a 100644 --- a/loleaflet/admin.strings.js +++ b/loleaflet/admin.strings.js @@ -32,6 +32,10 @@ l10nstrings.strMemoryStatsCachesize = _('Cache size of memory statistics'); l10nstrings.strMemoryStatsInterval = _('Time interval of memory statistics (in ms)'); l10nstrings.strCpuStatsCachesize = _('Cache size of CPU statistics'); l10nstrings.strCpuStatsInterval = _('Time interval of CPU statistics (in ms)'); +l10nstrings.strLimitVirtMemMb = _('Maximum Document process virtual memory (in MB)'); +l10nstrings.strLimitDataMemKb = _('Maximum Document process data memory (in KB)'); +l10nstrings.strLimitStackMemKb = _('Maximum Document process stack memory (in KB)'); +l10nstrings.strLimitFileSizeMb = _('Maximum file size allowed to write to disk (in MB)'); if (module) { module.exports = l10nstrings; diff --git a/loleaflet/dist/admin/adminSettings.html b/loleaflet/dist/admin/adminSettings.html index baaeac99..668c67d9 100644 --- a/loleaflet/dist/admin/adminSettings.html +++ b/loleaflet/dist/admin/adminSettings.html @@ -84,6 +84,14 @@ <input type="text" id="cpu_stats_size" name="Cpu Stats Size"><br/> <label for="cpu_stats_interval"><script>document.write(l10nstrings.strCpuStatsInterval)</script></label> <input type="text" id="cpu_stats_interval" name="Cpu Stats Interval"><br/> + <label for="limit_virt_mem_mb"><script>document.write(l10nstrings.strLimitVirtMemMb)</script></label> + <input type="text" id="limit_virt_mem_mb" name="Max Document Virtual Memory MB"><br/> + <label for="limit_data_mem_kb"><script>document.write(l10nstrings.strLimitDataMemKb)</script></label> + <input type="text" id="limit_data_mem_kb" name="Max Document Data Memory KB"><br/> + <label for="limit_stack_mem_kb"><script>document.write(l10nstrings.strLimitStackMemKb)</script></label> + <input type="text" id="limit_stack_mem_kb" name="Max Document Stack Memory Kb"><br/> + <label for="limit_file_size_mb"><script>document.write(l10nstrings.strLimitFileSizeMb)</script></label> + <input type="text" id="limit_file_size_mb" name="Max File Write Size Mb"><br/> <script>document.write('<input type="submit" value="' + l10nstrings.strSave + '"/><br/>')</script> </form> <br /> diff --git a/loleaflet/src/admin/AdminSocketSettings.js b/loleaflet/src/admin/AdminSocketSettings.js index c03a05ba..27c0be90 100644 --- a/loleaflet/src/admin/AdminSocketSettings.js +++ b/loleaflet/src/admin/AdminSocketSettings.js @@ -23,6 +23,10 @@ var AdminSocketSettings = AdminSocketBase.extend({ command += ' mem_stats_interval=' + memStatsInterval; command += ' cpu_stats_size=' + cpuStatsSize; command += ' cpu_stats_interval=' + cpuStatsInterval; + command += ' limit_virt_mem_mb=' + $('#limit_virt_mem_mb').val(); + command += ' limit_data_mem_kb=' + $('#limit_data_mem_kb').val(); + command += ' limit_stack_mem_kb=' + $('#limit_stack_mem_kb').val(); + command += ' limit_file_size_mb=' + $('#limit_file_size_mb').val(); socketSettings.send(command); }); diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp index 425a352d..0fc64aaa 100644 --- a/wsd/Admin.cpp +++ b/wsd/Admin.cpp @@ -166,14 +166,19 @@ void AdminSocketHandler::handleMessage(bool /* fin */, WSOpCode /* code */, { // for now, we have only these settings std::ostringstream oss; - oss << tokens[0] << " " - << "mem_stats_size=" << model.query("mem_stats_size") << " " - << "mem_stats_interval=" << std::to_string(_admin->getMemStatsInterval()) << " " - << "cpu_stats_size=" << model.query("cpu_stats_size") << " " - << "cpu_stats_interval=" << std::to_string(_admin->getCpuStatsInterval()); - - std::string responseFrame = oss.str(); - sendTextFrame(responseFrame); + oss << "settings " + << "mem_stats_size=" << model.query("mem_stats_size") << ' ' + << "mem_stats_interval=" << std::to_string(_admin->getMemStatsInterval()) << ' ' + << "cpu_stats_size=" << model.query("cpu_stats_size") << ' ' + << "cpu_stats_interval=" << std::to_string(_admin->getCpuStatsInterval()) << ' '; + + const DocProcSettings& docProcSettings = _admin->getDefDocProcSettings(); + oss << "limit_virt_mem_mb=" << docProcSettings.LimitVirtMemMb << ' ' + << "limit_data_mem_kb=" << docProcSettings.LimitDataMemKb << ' ' + << "limit_stack_mem_kb=" << docProcSettings.LimitStackMemKb << ' ' + << "limit_file_size_mb=" << docProcSettings.LimitFileSizeMb << ' '; + + sendTextFrame(oss.str()); } else if (tokens[0] == "shutdown") { @@ -187,7 +192,7 @@ void AdminSocketHandler::handleMessage(bool /* fin */, WSOpCode /* code */, for (size_t i = 1; i < tokens.count(); i++) { StringTokenizer setting(tokens[i], "=", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); - unsigned settingVal = 0; + int settingVal = 0; try { settingVal = std::stoi(setting[1]); @@ -199,38 +204,66 @@ void AdminSocketHandler::handleMessage(bool /* fin */, WSOpCode /* code */, return; } - if (setting[0] == "mem_stats_size") + const std::string settingName = setting[0]; + if (settingName == "mem_stats_size") { - if (settingVal != static_cast<unsigned>(std::stoi(model.query(setting[0])))) + if (settingVal != std::stoi(model.query(settingName))) { model.setMemStatsSize(settingVal); } } - else if (setting[0] == "mem_stats_interval") + else if (settingName == "mem_stats_interval") { - if (settingVal != _admin->getMemStatsInterval()) + if (settingVal != static_cast<int>(_admin->getMemStatsInterval())) { _admin->rescheduleMemTimer(settingVal); model.clearMemStats(); model.notify("settings mem_stats_interval=" + std::to_string(settingVal)); } } - else if (setting[0] == "cpu_stats_size") + else if (settingName == "cpu_stats_size") { - if (settingVal != static_cast<unsigned>(std::stoi(model.query(setting[0])))) + if (settingVal != std::stoi(model.query(settingName))) { model.setCpuStatsSize(settingVal); } } - else if (setting[0] == "cpu_stats_interval") + else if (settingName == "cpu_stats_interval") { - if (settingVal != _admin->getCpuStatsInterval()) + if (settingVal != static_cast<int>(_admin->getCpuStatsInterval())) { _admin->rescheduleCpuTimer(settingVal); model.clearCpuStats(); model.notify("settings cpu_stats_interval=" + std::to_string(settingVal)); } } + else if (LOOLProtocol::matchPrefix("limit_", settingName)) + { + DocProcSettings docProcSettings = _admin->getDefDocProcSettings(); + if (settingName == "limit_virt_mem_mb") + { + docProcSettings.LimitVirtMemMb = settingVal; + } + else if (settingName == "limit_data_mem_kb") + { + docProcSettings.LimitDataMemKb = settingVal; + } + else if (settingName == "limit_stack_mem_kb") + { + docProcSettings.LimitStackMemKb = settingVal; + } + else if (settingName == "limit_file_size_mb") + { + docProcSettings.LimitFileSizeMb = settingVal; + } + else + { + LOG_ERR("Unknown limit: " << settingName); + } + + model.notify("settings " + settingName + '=' + std::to_string(settingVal)); + _admin->setDefDocProcSettings(docProcSettings); + } } } } diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp index 91df8108..4faa3df2 100644 --- a/wsd/Admin.hpp +++ b/wsd/Admin.hpp @@ -104,6 +104,9 @@ public: void dumpState(std::ostream& os) override; + const DocProcSettings& getDefDocProcSettings() const { return _defDocProcSettings; } + void setDefDocProcSettings(const DocProcSettings& docProcSettings) { _defDocProcSettings = docProcSettings; } + private: /// The model is accessed only during startup & in /// the Admin Poll thread. @@ -114,6 +117,8 @@ private: std::atomic<int> _memStatsTaskIntervalMs; std::atomic<int> _cpuStatsTaskIntervalMs; + + DocProcSettings _defDocProcSettings; }; #endif diff --git a/wsd/AdminModel.hpp b/wsd/AdminModel.hpp index 90716964..96231bda 100644 --- a/wsd/AdminModel.hpp +++ b/wsd/AdminModel.hpp @@ -43,6 +43,14 @@ private: std::time_t _end = 0; }; +struct DocProcSettings +{ + size_t LimitVirtMemMb; + size_t LimitDataMemKb; + size_t LimitStackMemKb; + size_t LimitFileSizeMb; +}; + /// A document in Admin controller. class Document { @@ -100,6 +108,9 @@ public: _recvBytes += recv; } + const DocProcSettings& getDocProcSettings() const { return _docProcSettings; } + void setDocProcSettings(const DocProcSettings& docProcSettings) { _docProcSettings = docProcSettings; } + std::string to_string() const; private: @@ -124,6 +135,9 @@ private: /// Total bytes sent and recv'd by this document. uint64_t _sentBytes, _recvBytes; + + /// Per-doc kit process settings. + DocProcSettings _docProcSettings; }; /// An Admin session subscriber. diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index 4033a876..bdc10893 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -811,7 +811,7 @@ void LOOLWSD::initialize(Application& self) std::cerr << "\nLaunch this in your browser:\n\n" << getLaunchURI() << '\n' << std::endl; - std::string adminURI = getAdminURI(config()); + const std::string adminURI = getAdminURI(config()); if (!adminURI.empty()) std::cerr << "\nOr for the Admin Console:\n\n" << adminURI << '\n' << std::endl; @@ -1163,11 +1163,18 @@ bool LOOLWSD::createForKit() args.push_back("--clientport=" + std::to_string(ClientPortNumber)); args.push_back("--masterport=" + std::to_string(MasterPortNumber)); + DocProcSettings docProcSettings; + docProcSettings.LimitVirtMemMb = getConfigValue<int>("per_document.limit_virt_mem_mb", 0); + docProcSettings.LimitDataMemKb = getConfigValue<int>("per_document.limit_data_mem_kb", 0); + docProcSettings.LimitStackMemKb = getConfigValue<int>("per_document.limit_stack_mem_kb", 0); + docProcSettings.LimitFileSizeMb = getConfigValue<int>("per_document.limit_file_size_mb", 0); + Admin::instance().setDefDocProcSettings(docProcSettings); + std::ostringstream ossRLimits; - ossRLimits << "limit_virt_mem_mb:" << getConfigValue<int>("per_document.limit_virt_mem_mb", 0); - ossRLimits << ";limit_data_mem_kb:" << getConfigValue<int>("per_document.limit_data_mem_kb", 0); - ossRLimits << ";limit_stack_mem_kb:" << getConfigValue<int>("per_document.limit_stack_mem_kb", 0); - ossRLimits << ";limit_file_size_mb:" << getConfigValue<int>("per_document.limit_file_size_mb", 0); + ossRLimits << "limit_virt_mem_mb:" << docProcSettings.LimitVirtMemMb; + ossRLimits << ";limit_data_mem_kb:" << docProcSettings.LimitDataMemKb; + ossRLimits << ";limit_stack_mem_kb:" << docProcSettings.LimitStackMemKb; + ossRLimits << ";limit_file_size_mb:" << docProcSettings.LimitFileSizeMb; args.push_back("--rlimits=" + ossRLimits.str()); if (UnitWSD::get().hasKitHooks()) commit 36fb1e64f0b707420ed9cc775af8b10767375746 Author: Ashod Nakashian <[email protected]> Date: Sun Jun 11 11:54:46 2017 -0400 wsd: new internal command to change config values Change-Id: I8b4a573ba7b01ee6e7b3b91a00e12cc744f85fa8 Reviewed-on: https://gerrit.libreoffice.org/38676 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp index 9aa83a20..ed3d2f2a 100644 --- a/kit/ForKit.cpp +++ b/kit/ForKit.cpp @@ -111,6 +111,18 @@ public: LOG_WRN("Cannot spawn " << tokens[1] << " children as requested."); } } + else if (tokens.size() == 3 && tokens[0] == "setconfig") + { + // Currently onlly rlimit entries are supported. + if (!Seccomp::handleSetrlimitCommand(tokens)) + { + LOG_ERR("Unknown setconfig command: " << message); + } + } + else + { + LOG_ERR("Unknown command: " << message); + } } catch (const std::exception& exc) { diff --git a/kit/Kit.cpp b/kit/Kit.cpp index e6c56b5e..b445c31f 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -1831,7 +1831,7 @@ void lokit_main(const std::string& childRoot, #endif LOG_DBG(socketName << ": recv [" << LOOLProtocol::getAbbreviatedMessage(message) << "]."); - StringTokenizer tokens(message, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + std::vector<std::string> tokens = LOOLProtocol::tokenize(message); // Note: Syntax or parsing errors here are unexpected and fatal. if (TerminationFlag) @@ -1877,6 +1877,14 @@ void lokit_main(const std::string& childRoot, LOG_WRN("No document while processing " << tokens[0] << " request."); } } + else if (tokens.size() == 3 && tokens[0] == "setconfig") + { + // Currently onlly rlimit entries are supported. + if (!Seccomp::handleSetrlimitCommand(tokens)) + { + LOG_ERR("Unknown setconfig command: " << message); + } + } else { LOG_ERR("Bad or unknown token [" << tokens[0] << "]"); commit 6de3adcf9ce385152412a7a062245cb751a69cb6 Author: Ashod Nakashian <[email protected]> Date: Sun Jun 11 11:48:24 2017 -0400 wsd: pass default rlimits to forkit from config Change-Id: I84d271f460f0fb1d03a973107c32265d84bf2841 Reviewed-on: https://gerrit.libreoffice.org/38675 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/common/Protocol.hpp b/common/Protocol.hpp index cae54d46..e26703d5 100644 --- a/common/Protocol.hpp +++ b/common/Protocol.hpp @@ -161,6 +161,21 @@ namespace LOOLProtocol return std::string(message, size); } + /// Split a string in two at the delimeter, removing it. + inline + std::pair<std::string, std::string> split(const char* s, const int length, const char delimeter = ' ') + { + const auto size = getDelimiterPosition(s, length, delimeter); + return std::make_pair(std::string(s, size), std::string(s+size+1)); + } + + /// Split a string in two at the delimeter, removing it. + inline + std::pair<std::string, std::string> split(const std::string& s, const char delimeter = ' ') + { + return split(s.c_str(), s.size(), delimeter); + } + /// Returns the first token of a message. inline std::string getFirstToken(const char *message, const int length, const char delim = ' ') diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp index ab11f626..9aa83a20 100644 --- a/kit/ForKit.cpp +++ b/kit/ForKit.cpp @@ -37,6 +37,7 @@ #include "Util.hpp" #include "common/FileUtil.hpp" +#include "common/Seccomp.hpp" #include "common/SigUtil.hpp" #include "security.h" @@ -419,6 +420,21 @@ int main(int argc, char** argv) std::cout << "loolforkit version details: " << version << " - " << hash << std::endl; DisplayVersion = true; } + else if (std::strstr(cmd, "--rlimits") == cmd) + { + eq = std::strchr(cmd, '='); + const std::string rlimits = std::string(eq+1); + std::vector<std::string> tokens = LOOLProtocol::tokenize(rlimits, ';'); + for (const std::string& cmdLimit : tokens) + { + const auto pair = LOOLProtocol::split(cmdLimit, ':'); + std::vector<std::string> tokensLimit = { "setconfig", pair.first, pair.second }; + if (!Seccomp::handleSetrlimitCommand(tokensLimit)) + { + LOG_ERR("Unknown rlimits command: " << cmdLimit); + } + } + } #if ENABLE_DEBUG // this process has various privileges - don't run arbitrary code. else if (std::strstr(cmd, "--unitlib=") == cmd) diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index e8e3acc2..4033a876 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -1162,6 +1162,14 @@ bool LOOLWSD::createForKit() args.push_back("--childroot=" + ChildRoot); args.push_back("--clientport=" + std::to_string(ClientPortNumber)); args.push_back("--masterport=" + std::to_string(MasterPortNumber)); + + std::ostringstream ossRLimits; + ossRLimits << "limit_virt_mem_mb:" << getConfigValue<int>("per_document.limit_virt_mem_mb", 0); + ossRLimits << ";limit_data_mem_kb:" << getConfigValue<int>("per_document.limit_data_mem_kb", 0); + ossRLimits << ";limit_stack_mem_kb:" << getConfigValue<int>("per_document.limit_stack_mem_kb", 0); + ossRLimits << ";limit_file_size_mb:" << getConfigValue<int>("per_document.limit_file_size_mb", 0); + args.push_back("--rlimits=" + ossRLimits.str()); + if (UnitWSD::get().hasKitHooks()) { args.push_back("--unitlib=" + UnitTestLibrary); diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp index a608c6c1..d98ecebe 100644 --- a/wsd/LOOLWSD.hpp +++ b/wsd/LOOLWSD.hpp @@ -166,7 +166,7 @@ private: ConfigValueGetter(config, name)(value); return true; } - catch (const Poco::SyntaxException&) + catch (const std::exception&) { } commit 42969b732c312215a2955f3b85139a9e7e2fab19 Author: Ashod Nakashian <[email protected]> Date: Sun Jun 11 11:47:23 2017 -0400 wsd: log the relevant rlimits at Kit startup Change-Id: I6ada56d9bda80301ab55de2c831452b21aa362c1 Reviewed-on: https://gerrit.libreoffice.org/38674 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 0358e7f9..e6c56b5e 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -19,6 +19,8 @@ #include <sys/capability.h> #include <unistd.h> #include <utime.h> +#include <sys/time.h> +#include <sys/resource.h> #include <atomic> #include <cassert> @@ -1764,6 +1766,27 @@ void lokit_main(const std::string& childRoot, std::_Exit(Application::EXIT_SOFTWARE); } + rlimit rlim = { 0, 0 }; + if (getrlimit(RLIMIT_AS, &rlim) == 0) + LOG_INF("RLIMIT_AS is " << rlim.rlim_max << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_AS."); + + if (getrlimit(RLIMIT_DATA, &rlim) == 0) + LOG_INF("RLIMIT_DATA is " << rlim.rlim_max << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_DATA."); + + if (getrlimit(RLIMIT_STACK, &rlim) == 0) + LOG_INF("RLIMIT_STACK is " << rlim.rlim_max << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_STACK."); + + if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) + LOG_INF("RLIMIT_NOFILE is " << rlim.rlim_max << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_NOFILE."); + assert(loKit); LOG_INF("Process is ready."); commit 9cb82cebe3edf1e6d9c6cac6e433abbc638c26f6 Author: Ashod Nakashian <[email protected]> Date: Sun Jun 11 11:39:15 2017 -0400 wsd: add rlimit config entries and defaults Change-Id: I8cb498d01bc1a7a55d168e49c754bb1bba80aea1 Reviewed-on: https://gerrit.libreoffice.org/38673 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/loolwsd.xml.in b/loolwsd.xml.in index eed51283..8ec29c82 100644 --- a/loolwsd.xml.in +++ b/loolwsd.xml.in @@ -15,6 +15,10 @@ <per_document desc="Document-specific settings, including LO Core settings."> <max_concurrency desc="The maximum number of threads to use while processing a document." type="uint" default="4">4</max_concurrency> <idle_timeout_secs desc="The maximum number of seconds before unloading an idle document. Defaults to 1 hour." type="uint" default="3600">3600</idle_timeout_secs> + <limit_virt_mem_kb desc="The maximum virtual memory allowed to each document process. 0 for unlimited, 1700 min." type="uint">0</limit_virt_mem_kb> + <limit_data_mem_kb desc="The maximum memory data segment allowed to each document process. 0 for unlimited." type="uint">0</limit_data_mem_kb> + <limit_stack_mem_kb desc="The maximum stack size allowed to each document process. 0 for unlimited." type="uint">8000</limit_stack_mem_kb> + <limit_file_size_mb desc="The maximum file size allowed to each documen process to write. 0 for unlimited." type="uint">50</limit_file_size_mb> </per_document> <per_view desc="View-specific settings."> diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index 07d371c8..e8e3acc2 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -624,6 +624,10 @@ void LOOLWSD::initialize(Application& self) { "num_prespawn_children", "1" }, { "per_document.max_concurrency", "4" }, { "per_document.idle_timeout_secs", "3600" }, + { "per_document.limit_virt_mem_mb", "0" }, + { "per_document.limit_data_mem_kb", "0" }, + { "per_document.limit_stack_mem_kb", "8000" }, + { "per_document.limit_file_size_mb", "50" }, { "per_view.out_of_focus_timeout_secs", "60" }, { "per_view.idle_timeout_secs", "900" }, { "loleaflet_html", "loleaflet.html" }, commit 92d29b1ce752f9562d6a98e5219bbcac6197d431 Author: Ashod Nakashian <[email protected]> Date: Sat Jun 10 20:41:30 2017 -0400 wsd: support setting process rlimits Change-Id: I7117e6843d2ebc919d7d2303cc593de888cc54b1 Reviewed-on: https://gerrit.libreoffice.org/38672 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/common/Seccomp.cpp b/common/Seccomp.cpp index 092f1a5d..52fedb01 100644 --- a/common/Seccomp.cpp +++ b/common/Seccomp.cpp @@ -15,15 +15,17 @@ #include <dlfcn.h> #include <ftw.h> +#include <linux/audit.h> +#include <linux/filter.h> +#include <linux/seccomp.h> #include <malloc.h> +#include <signal.h> #include <sys/capability.h> +#include <sys/prctl.h> +#include <sys/resource.h> +#include <sys/time.h> #include <unistd.h> #include <utime.h> -#include <signal.h> -#include <sys/prctl.h> -#include <linux/audit.h> -#include <linux/filter.h> -#include <linux/seccomp.h> #include <common/Log.hpp> #include <common/SigUtil.hpp> @@ -214,6 +216,83 @@ bool lockdown(Type type) return true; } +bool handleSetrlimitCommand(const std::vector<std::string>& tokens) +{ + if (tokens.size() == 3 && tokens[0] == "setconfig") + { + if (tokens[1] == "limit_virt_mem_mb") + { + rlim_t lim = std::stoi(tokens[2]) * 1024 * 1024; + if (lim <= 0) + lim = RLIM_INFINITY; + + rlimit rlim = { lim, lim }; + if (setrlimit(RLIMIT_AS, &rlim) != 0) + LOG_SYS("Failed to set RLIMIT_AS to " << lim << " bytes."); + + if (getrlimit(RLIMIT_AS, &rlim) == 0) + LOG_INF("RLIMIT_AS is " << rlim.rlim_max << " bytes after setting it to " << lim << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_AS."); + + return true; + } + else if (tokens[1] == "limit_data_mem_kb") + { + rlim_t lim = std::stoi(tokens[2]) * 1024; + if (lim <= 0) + lim = RLIM_INFINITY; + + rlimit rlim = { lim, lim }; + if (setrlimit(RLIMIT_DATA, &rlim) != 0) + LOG_SYS("Failed to set RLIMIT_DATA to " << lim << " bytes."); + + if (getrlimit(RLIMIT_DATA, &rlim) == 0) + LOG_INF("RLIMIT_DATA is " << rlim.rlim_max << " bytes after setting it to " << lim << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_DATA."); + + return true; + } + else if (tokens[1] == "limit_stack_mem_kb") + { + rlim_t lim = std::stoi(tokens[2]) * 1024; + if (lim <= 0) + lim = RLIM_INFINITY; + + rlimit rlim = { lim, lim }; + if (setrlimit(RLIMIT_STACK, &rlim) != 0) + LOG_SYS("Failed to set RLIMIT_STACK to " << lim << " bytes."); + + if (getrlimit(RLIMIT_STACK, &rlim) == 0) + LOG_INF("RLIMIT_STACK is " << rlim.rlim_max << " bytes after setting it to " << lim << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_STACK."); + + return true; + } + else if (tokens[1] == "limit_file_size_mb") + { + rlim_t lim = std::stoi(tokens[2]) * 1024 * 1024; + if (lim <= 0) + lim = RLIM_INFINITY; + + rlimit rlim = { lim, lim }; + if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) + LOG_SYS("Failed to set RLIMIT_NOFILE to " << lim << " bytes."); + + if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) + LOG_INF("RLIMIT_NOFILE is " << rlim.rlim_max << " bytes after setting it to " << lim << " bytes."); + else + LOG_SYS("Failed to get RLIMIT_NOFILE."); + + return true; + } + } + + return false; +} + } // namespace Seccomp /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/Seccomp.hpp b/common/Seccomp.hpp index 865b5c91..f6d1a130 100644 --- a/common/Seccomp.hpp +++ b/common/Seccomp.hpp @@ -14,6 +14,10 @@ namespace Seccomp { /// Lock-down a process hard - @returns true on success. bool lockdown(Type type); + + /// Handles setconfig command with limit_... subcommands. + /// Returns true iff it handled the command, regardless of success/failure. + bool handleSetrlimitCommand(const std::vector<std::string>& tokens); }; #endif _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
