/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
var Os = require('os');
var TEST_PROGRAM = [
"#include ",
"#include ",
"#include ",
"#include ",
"#include ",
"#include ",
"int main() {",
" return __NR_read",
" | PR_SET_NO_NEW_PRIVS | PR_SET_SECCOMP | AUDIT_ARCH_X86_64",
" | BPF_K | SECCOMP_MODE_FILTER;",
"}"
].join('\n');
var pushLinks = function (builder) {
builder.Seccomp_QUEUE.forEach(function (file) {
if (builder.Seccomp_EXISTS) {
file.links.push("util/Seccomp.c");
} else {
file.links.push("util/Seccomp_dummy.c");
}
});
builder.Seccomp_QUEUE = undefined;
};
// Turns a version string into an array of integers
// 1.2.3-4-generic-x-5 -> [1, 2, 3, 4, 5]
// 1.2.3-xx-14.2 -> [1, 2, 3, 14, 2]
// 3.2.0-23-generic-pae -> [3, 2, 0, 23]
var version_to_array = function (version) {
var ver_list =
version.replace(/[^0-9]/g, '.').replace(/\.+/g, '.').replace(/\.$/, '').split('.');
for (var i = 0; i < ver_list.length; i++) {
ver_list[i] = Number(ver_list[i]);
}
return ver_list;
};
// Compares two arrays of integers
// Returns
// -1 for version1 < version2
// 0 for version1 == version2
// 1 for version1 > version2
var compare_versions = function (version1, version2) {
if (version1.length === 0 && version2.length === 0) {
return 0;
} else if (version1.length === 0) {
return (version2[0] === 0) ? 0 : 1;
} else if (version2.length === 0) {
return (version1[0] === 0) ? 0 : -1;
} else if (version1[0] === version2[0]) {
return compare_versions(version1.splice(1), version2.splice(1));
} else {
return (version1[0] < version2[0]) ? -1 : 1;
}
};
var seccomp_version_check = function (version) {
var ver_list = version_to_array(version);
return compare_versions(ver_list, [3, 5, 0]);
};
var detect = module.exports.detect = function (async, file, builder)
{
if (typeof(builder.Seccomp_QUEUE) !== 'undefined') {
builder.Seccomp_QUEUE.push(file);
return;
}
builder.Seccomp_QUEUE = [ file ];
if (typeof(builder.Seccomp_EXISTS) !== 'undefined') {
pushLinks(builder);
return;
}
console.log("Searching for SECCOMP");
var hasSeccomp = false;
var osversion = Os.release();
if (builder.config.systemName !== 'linux') {
console.log("SECCOMP is only available on linux");
} else if (process.env['Seccomp_NO']) {
console.log("SECCOMP disabled");
} else if (!builder.config.crossCompiling && (seccomp_version_check(osversion) === -1)) {
console.log("SECCOMP filtering is only available in Linux 3.5+");
} else {
var done = async();
var CanCompile = require('../node_build/CanCompile');
var cflags = [ builder.config.cflags, '-x', 'c' ];
CanCompile.check(builder, TEST_PROGRAM, cflags, function (err, can) {
builder.Seccomp_EXISTS = !!can;
if (!can) {
console.log("Failed to get SECCOMP, compile failure: [" + err + "]");
}
pushLinks(builder);
done();
});
return;
}
builder.Seccomp_EXISTS = hasSeccomp;
pushLinks(builder);
};