[Libreoffice-commits] online.git: 7 commits - common/Protocol.hpp common/Seccomp.cpp common/Seccomp.hpp kit/ForKit.cpp kit/Kit.cpp loleaflet/admin.strings.js loleaflet/dist loleaflet/src loolwsd.xml.in wsd/Admin.cpp wsd/Admin.hpp wsd/AdminModel.hpp wsd/LOOLWSD.cpp wsd/LOOLWSD.hpp

Ashod Nakashian ashod.nakashian at collabora.co.uk
Mon Jun 12 05:08:00 UTC 2017


 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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

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


More information about the Libreoffice-commits mailing list