Seccomp.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. var Os = require('os');
  16. var TEST_PROGRAM = [
  17. "#include <sys/resource.h>",
  18. "#include <sys/prctl.h>",
  19. "#include <linux/filter.h>",
  20. "#include <linux/seccomp.h>",
  21. "#include <linux/audit.h>",
  22. "#include <sys/syscall.h>",
  23. "int main() {",
  24. " return __NR_read",
  25. " | PR_SET_NO_NEW_PRIVS | PR_SET_SECCOMP | AUDIT_ARCH_X86_64",
  26. " | BPF_K | SECCOMP_MODE_FILTER;",
  27. "}"
  28. ].join('\n');
  29. var pushLinks = function (builder) {
  30. builder.Seccomp_QUEUE.forEach(function (file) {
  31. if (builder.Seccomp_EXISTS) {
  32. file.links.push("util/Seccomp.c");
  33. } else {
  34. file.links.push("util/Seccomp_dummy.c");
  35. }
  36. });
  37. builder.Seccomp_QUEUE = undefined;
  38. };
  39. // Turns a version string into an array of integers
  40. // 1.2.3-4-generic-x-5 -> [1, 2, 3, 4, 5]
  41. // 1.2.3-xx-14.2 -> [1, 2, 3, 14, 2]
  42. // 3.2.0-23-generic-pae -> [3, 2, 0, 23]
  43. var version_to_array = function (version) {
  44. var ver_list =
  45. version.replace(/[^0-9]/g, '.').replace(/\.+/g, '.').replace(/\.$/, '').split('.');
  46. for (var i = 0; i < ver_list.length; i++) {
  47. ver_list[i] = Number(ver_list[i]);
  48. }
  49. return ver_list;
  50. };
  51. // Compares two arrays of integers
  52. // Returns
  53. // -1 for version1 < version2
  54. // 0 for version1 == version2
  55. // 1 for version1 > version2
  56. var compare_versions = function (version1, version2) {
  57. if (version1.length === 0 && version2.length === 0) {
  58. return 0;
  59. } else if (version1.length === 0) {
  60. return (version2[0] === 0) ? 0 : 1;
  61. } else if (version2.length === 0) {
  62. return (version1[0] === 0) ? 0 : -1;
  63. } else if (version1[0] === version2[0]) {
  64. return compare_versions(version1.splice(1), version2.splice(1));
  65. } else {
  66. return (version1[0] < version2[0]) ? -1 : 1;
  67. }
  68. };
  69. var seccomp_version_check = function (version) {
  70. var ver_list = version_to_array(version);
  71. return compare_versions(ver_list, [3, 5, 0]);
  72. };
  73. var detect = module.exports.detect = function (async, file, builder)
  74. {
  75. if (typeof(builder.Seccomp_QUEUE) !== 'undefined') {
  76. builder.Seccomp_QUEUE.push(file);
  77. return;
  78. }
  79. builder.Seccomp_QUEUE = [ file ];
  80. if (typeof(builder.Seccomp_EXISTS) !== 'undefined') {
  81. pushLinks(builder);
  82. return;
  83. }
  84. console.log("Searching for SECCOMP");
  85. var hasSeccomp = false;
  86. var osversion = Os.release();
  87. if (builder.config.systemName !== 'linux') {
  88. console.log("SECCOMP is only available on linux");
  89. } else if (process.env['Seccomp_NO']) {
  90. console.log("SECCOMP disabled");
  91. } else if (!builder.config.crossCompiling && (seccomp_version_check(osversion) === -1)) {
  92. console.log("SECCOMP filtering is only available in Linux 3.5+");
  93. } else {
  94. var done = async();
  95. var CanCompile = require('../node_build/CanCompile');
  96. var cflags = [ builder.config.cflags, '-x', 'c' ];
  97. CanCompile.check(builder, TEST_PROGRAM, cflags, function (err, can) {
  98. builder.Seccomp_EXISTS = !!can;
  99. if (!can) {
  100. console.log("Failed to get SECCOMP, compile failure: [" + err + "]");
  101. }
  102. pushLinks(builder);
  103. done();
  104. });
  105. return;
  106. }
  107. builder.Seccomp_EXISTS = hasSeccomp;
  108. pushLinks(builder);
  109. };