2015-05-15 05:44:48 +08:00
|
|
|
/*
|
|
|
|
|
|
|
|
nsjail
|
|
|
|
-----------------------------------------
|
|
|
|
|
|
|
|
Copyright 2014 Google Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
|
|
|
|
*/
|
2016-03-02 00:03:11 +08:00
|
|
|
|
2015-05-15 05:44:48 +08:00
|
|
|
#include "nsjail.h"
|
|
|
|
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
2017-09-14 04:03:21 +08:00
|
|
|
#include <stdlib.h>
|
2015-05-15 05:44:48 +08:00
|
|
|
#include <string.h>
|
2018-05-25 07:04:29 +08:00
|
|
|
#include <sys/ioctl.h>
|
2015-05-15 05:44:48 +08:00
|
|
|
#include <sys/time.h>
|
2018-05-25 07:04:29 +08:00
|
|
|
#include <termios.h>
|
2015-05-15 05:44:48 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2018-05-28 08:04:03 +08:00
|
|
|
#include <memory>
|
|
|
|
|
2015-05-15 05:44:48 +08:00
|
|
|
#include "cmdline.h"
|
2018-02-11 00:49:15 +08:00
|
|
|
#include "logs.h"
|
2018-02-10 12:25:55 +08:00
|
|
|
#include "macros.h"
|
2015-05-15 05:44:48 +08:00
|
|
|
#include "net.h"
|
2018-02-12 10:11:58 +08:00
|
|
|
#include "sandbox.h"
|
2015-05-15 05:44:48 +08:00
|
|
|
#include "subproc.h"
|
2017-06-20 06:16:38 +08:00
|
|
|
#include "util.h"
|
2015-05-15 05:44:48 +08:00
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
namespace nsjail {
|
2015-05-15 05:44:48 +08:00
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
static __thread int sigFatal = 0;
|
|
|
|
static __thread bool showProc = false;
|
|
|
|
|
|
|
|
static void sigHandler(int sig) {
|
2015-05-15 05:44:48 +08:00
|
|
|
if (sig == SIGALRM) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sig == SIGCHLD) {
|
|
|
|
return;
|
|
|
|
}
|
2017-10-19 21:25:20 +08:00
|
|
|
if (sig == SIGUSR1 || sig == SIGQUIT) {
|
2018-05-25 08:15:47 +08:00
|
|
|
showProc = true;
|
2015-05-15 05:44:48 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-05-25 08:15:47 +08:00
|
|
|
sigFatal = sig;
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
static bool setSigHandler(int sig) {
|
2018-02-11 04:19:47 +08:00
|
|
|
LOG_D("Setting sighandler for signal %s (%d)", util::sigName(sig).c_str(), sig);
|
2015-05-15 05:44:48 +08:00
|
|
|
|
|
|
|
sigset_t smask;
|
|
|
|
sigemptyset(&smask);
|
2018-02-08 22:24:17 +08:00
|
|
|
|
|
|
|
struct sigaction sa;
|
2018-05-25 08:15:47 +08:00
|
|
|
sa.sa_handler = sigHandler;
|
2018-02-08 22:24:17 +08:00
|
|
|
sa.sa_mask = smask;
|
|
|
|
sa.sa_flags = 0;
|
|
|
|
sa.sa_restorer = NULL;
|
2018-02-15 08:33:33 +08:00
|
|
|
|
|
|
|
if (sig == SIGTTIN || sig == SIGTTOU) {
|
|
|
|
sa.sa_handler = SIG_IGN;
|
|
|
|
};
|
2015-05-15 05:44:48 +08:00
|
|
|
if (sigaction(sig, &sa, NULL) == -1) {
|
|
|
|
PLOG_E("sigaction(%d)", sig);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
static bool setSigHandlers(void) {
|
2018-05-22 20:27:18 +08:00
|
|
|
for (const auto& i : nssigs) {
|
2018-05-25 08:15:47 +08:00
|
|
|
if (!setSigHandler(i)) {
|
2017-10-18 18:33:24 +08:00
|
|
|
return false;
|
|
|
|
}
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
static bool setTimer(nsjconf_t* nsjconf) {
|
2015-08-15 22:02:38 +08:00
|
|
|
if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-15 05:44:48 +08:00
|
|
|
struct itimerval it = {
|
2018-02-08 22:24:17 +08:00
|
|
|
.it_interval =
|
2017-10-26 06:26:02 +08:00
|
|
|
{
|
2017-10-16 21:31:14 +08:00
|
|
|
.tv_sec = 1,
|
|
|
|
.tv_usec = 0,
|
|
|
|
},
|
2018-02-08 22:24:17 +08:00
|
|
|
.it_value =
|
2017-10-26 06:26:02 +08:00
|
|
|
{
|
2017-10-16 21:31:14 +08:00
|
|
|
.tv_sec = 1,
|
|
|
|
.tv_usec = 0,
|
|
|
|
},
|
2015-05-15 05:44:48 +08:00
|
|
|
};
|
|
|
|
if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
|
|
|
|
PLOG_E("setitimer(ITIMER_REAL)");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-26 07:24:58 +08:00
|
|
|
static int listenMode(nsjconf_t* nsjconf) {
|
2018-02-11 06:46:15 +08:00
|
|
|
int listenfd = net::getRecvSocket(nsjconf->bindhost.c_str(), nsjconf->port);
|
2015-05-15 05:44:48 +08:00
|
|
|
if (listenfd == -1) {
|
2018-05-28 07:40:02 +08:00
|
|
|
return EXIT_FAILURE;
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
|
|
|
for (;;) {
|
2018-05-25 08:15:47 +08:00
|
|
|
if (sigFatal > 0) {
|
2018-07-27 19:33:39 +08:00
|
|
|
subproc::killAndReapAll(nsjconf);
|
2018-05-25 08:15:47 +08:00
|
|
|
logs::logStop(sigFatal);
|
2016-07-29 21:38:22 +08:00
|
|
|
close(listenfd);
|
2018-05-28 07:40:02 +08:00
|
|
|
return EXIT_SUCCESS;
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
2018-05-25 08:15:47 +08:00
|
|
|
if (showProc) {
|
|
|
|
showProc = false;
|
2018-02-10 00:03:02 +08:00
|
|
|
subproc::displayProc(nsjconf);
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
2018-02-10 00:27:28 +08:00
|
|
|
int connfd = net::acceptConn(listenfd);
|
2015-05-15 05:44:48 +08:00
|
|
|
if (connfd >= 0) {
|
2018-02-10 00:03:02 +08:00
|
|
|
subproc::runChild(nsjconf, connfd, connfd, connfd);
|
2015-05-15 05:44:48 +08:00
|
|
|
close(connfd);
|
|
|
|
}
|
2018-02-10 00:03:02 +08:00
|
|
|
subproc::reapProc(nsjconf);
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
static int standaloneMode(nsjconf_t* nsjconf) {
|
2015-05-15 05:44:48 +08:00
|
|
|
for (;;) {
|
2018-07-24 06:23:44 +08:00
|
|
|
if (!subproc::runChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) {
|
|
|
|
LOG_E("Couldn't launch the child process");
|
|
|
|
return 0xff;
|
|
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
int child_status = subproc::reapProc(nsjconf);
|
|
|
|
if (subproc::countProc(nsjconf) == 0) {
|
|
|
|
if (nsjconf->mode == MODE_STANDALONE_ONCE) {
|
|
|
|
return child_status;
|
|
|
|
}
|
|
|
|
break;
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
2018-07-24 06:23:44 +08:00
|
|
|
if (showProc) {
|
|
|
|
showProc = false;
|
|
|
|
subproc::displayProc(nsjconf);
|
2018-07-23 23:13:17 +08:00
|
|
|
}
|
2018-07-24 06:23:44 +08:00
|
|
|
if (sigFatal > 0) {
|
2018-07-27 19:33:39 +08:00
|
|
|
subproc::killAndReapAll(nsjconf);
|
2018-07-24 06:23:44 +08:00
|
|
|
logs::logStop(sigFatal);
|
|
|
|
return (128 + sigFatal);
|
|
|
|
}
|
|
|
|
pause();
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
|
|
|
}
|
2015-07-08 00:33:10 +08:00
|
|
|
// not reached
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
std::unique_ptr<struct termios> getTC(int fd) {
|
2018-05-25 07:04:29 +08:00
|
|
|
std::unique_ptr<struct termios> trm(new struct termios);
|
|
|
|
|
|
|
|
if (ioctl(fd, TCGETS, trm.get()) == -1) {
|
|
|
|
PLOG_D("ioctl(fd=%d, TCGETS) failed", fd);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-05-25 08:15:47 +08:00
|
|
|
LOG_D("Saved the current state of the TTY");
|
2018-05-25 07:04:29 +08:00
|
|
|
return trm;
|
|
|
|
}
|
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
void setTC(int fd, const struct termios* trm) {
|
2018-05-25 07:04:29 +08:00
|
|
|
if (!trm) {
|
|
|
|
return;
|
|
|
|
}
|
2018-05-25 08:05:12 +08:00
|
|
|
if (ioctl(fd, TCSETS, trm) == -1) {
|
2018-05-25 07:04:29 +08:00
|
|
|
PLOG_W("ioctl(fd=%d, TCSETS) failed", fd);
|
2018-05-25 08:15:47 +08:00
|
|
|
return;
|
2018-05-25 07:04:29 +08:00
|
|
|
}
|
2019-03-10 22:00:45 +08:00
|
|
|
if (tcflush(fd, TCIFLUSH) == -1) {
|
|
|
|
PLOG_W("tcflush(fd=%d, TCIFLUSH) failed", fd);
|
|
|
|
return;
|
|
|
|
}
|
2018-05-25 07:04:29 +08:00
|
|
|
}
|
|
|
|
|
2018-05-25 08:15:47 +08:00
|
|
|
} // namespace nsjail
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
int main(int argc, char* argv[]) {
|
2018-02-10 22:50:12 +08:00
|
|
|
std::unique_ptr<nsjconf_t> nsjconf = cmdline::parseArgs(argc, argv);
|
2018-05-25 08:15:47 +08:00
|
|
|
std::unique_ptr<struct termios> trm = nsjail::getTC(STDIN_FILENO);
|
2018-05-25 08:05:12 +08:00
|
|
|
|
2018-02-09 22:44:29 +08:00
|
|
|
if (!nsjconf) {
|
2017-09-25 18:00:57 +08:00
|
|
|
LOG_F("Couldn't parse cmdline options");
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
2018-02-09 22:44:29 +08:00
|
|
|
if (nsjconf->daemonize && (daemon(0, 0) == -1)) {
|
2015-05-15 05:44:48 +08:00
|
|
|
PLOG_F("daemon");
|
|
|
|
}
|
2018-02-09 22:44:29 +08:00
|
|
|
cmdline::logParams(nsjconf.get());
|
2018-05-25 08:15:47 +08:00
|
|
|
if (!nsjail::setSigHandlers()) {
|
|
|
|
LOG_F("nsjail::setSigHandlers() failed");
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
2018-05-25 08:15:47 +08:00
|
|
|
if (!nsjail::setTimer(nsjconf.get())) {
|
|
|
|
LOG_F("nsjail::setTimer() failed");
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
2018-02-12 10:11:58 +08:00
|
|
|
if (!sandbox::preparePolicy(nsjconf.get())) {
|
|
|
|
LOG_F("Couldn't prepare sandboxing policy");
|
|
|
|
}
|
2015-05-15 05:44:48 +08:00
|
|
|
|
2018-02-13 00:31:45 +08:00
|
|
|
int ret = 0;
|
2018-02-09 22:44:29 +08:00
|
|
|
if (nsjconf->mode == MODE_LISTEN_TCP) {
|
2018-05-26 07:24:58 +08:00
|
|
|
ret = nsjail::listenMode(nsjconf.get());
|
2015-05-15 05:44:48 +08:00
|
|
|
} else {
|
2018-05-25 08:15:47 +08:00
|
|
|
ret = nsjail::standaloneMode(nsjconf.get());
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|
2018-02-17 10:14:54 +08:00
|
|
|
|
2018-02-13 00:31:45 +08:00
|
|
|
sandbox::closePolicy(nsjconf.get());
|
2018-05-25 08:05:12 +08:00
|
|
|
/* Try to restore the underlying console's params in case some program has changed it */
|
2019-10-04 06:33:29 +08:00
|
|
|
if (!nsjconf->daemonize) {
|
|
|
|
nsjail::setTC(STDIN_FILENO, trm.get());
|
|
|
|
}
|
2018-05-25 07:04:29 +08:00
|
|
|
|
2018-05-28 08:04:03 +08:00
|
|
|
LOG_D("Returning with %d", ret);
|
2018-02-13 00:09:45 +08:00
|
|
|
return ret;
|
2015-05-15 05:44:48 +08:00
|
|
|
}
|