23.11.17 최초 작성
격리 (isolation) : 프로세스가 공유하는 부분 완전 격리 (보안을 위함)
(시스템 콜, PID, 파일 시스템, IP / Port)
독립적으로 소프트웨어 패키징 구축 가능
(운영체제 버전, 라이브러리, 패키지 등)
격리를 위한 방법
namespace : 시스템 리소스 (mount, UTS, PID, network 등)Control Groups : 리소스 제한 (Isolated Process)CapabilitiesSeccompchroot / pivot_rootmkdir("new")
chroot("new")
chdir("/") //new를 root 로 변경
pivot_root : chroot의 기능을 보완하기 위한 시스템 콜namespace에 의해 구분되는 것들PID networkuserUTSmountcgroupIPCclone : 새로운 프로세스 생성 (fork 보다 다양한 기능 제공)#define _GNU_SOURCE
#include <sched.h>
int clone(int (*func) (void *), void *child_stack, int flags, void *func_arg ...)
///
Return : Child의 PID
-1 : Error
t_clone : #define _GNU_SOURCE
#include <signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sched.h>
#include "tlpi_hdr.h"
#ifndef CHILD_SIG
#define CHILD_SIG SIGUSR1 /* Signal to be generated on termination
of cloned child */
#endif
static int /* Startup function for cloned child */
childFunc(void *arg)
{
if (close(*((int *) arg)) == -1)
errExit("close");
return 0; /* Child terminates now */
}
int
main(int argc, char *argv[])
{
const int STACK_SIZE = 65536; /* Stack size for cloned child */
char *stack; /* Start of stack buffer */
char *stackTop; /* End of stack buffer */
int s, fd, flags;
fd = open("/dev/null", O_RDWR); /* Child will close this fd */
if (fd == -1)
errExit("open");
/* If argc > 1, child shares file descriptor table with parent */
flags = (argc > 1) ? CLONE_FILES : 0;
/* Allocate stack for child */
stack = malloc(STACK_SIZE);
if (stack == NULL)
errExit("malloc");
stackTop = stack + STACK_SIZE; /* Assume stack grows downward */
/* Ignore CHILD_SIG, in case it is a signal whose default is to
terminate the process; but don't ignore SIGCHLD (which is ignored
by default), since that would prevent the creation of a zombie. */
if (CHILD_SIG != 0 && CHILD_SIG != SIGCHLD)
if (signal(CHILD_SIG, SIG_IGN) == SIG_ERR) errExit("signal");
/* Create child; child commences execution in childFunc() */
if (clone(childFunc, stackTop, flags | CHILD_SIG, (void *) &fd) == -1)
errExit("clone");
/* Parent falls through to here. Wait for child; __WCLONE is
needed for child notifying with signal other than SIGCHLD. */
if (waitpid(-1, NULL, (CHILD_SIG != SIGCHLD) ? __WCLONE : 0) == -1)
errExit("waitpid");
printf("child has terminated\n");
/* Did close() of file descriptor in child affect parent? */
s = write(fd, "x", 1);
if (s == -1 && errno == EBADF)
printf("file descriptor %d has been closed\n", fd);
else if (s == -1)
printf("write() on file descriptor %d failed "
"unexpectedly (%s)\n", fd, strerror(errno));
else
printf("write() on file descriptor %d succeeded\n", fd);
exit(EXIT_SUCCESS);
}
demo_uts_namespace : 호스트 이름이 다른 새로운 프로세스를 clone으로 생성해 부모와 자식 프로세스의 호스트 이름을 출력#define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sched.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
/* A simple error-handling function: print an error message based
on the value in 'errno' and terminate the calling process */
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static int /* Start function for cloned child */
childFunc(void *arg)
{
/* Change hostname in UTS namespace of child */
if (sethostname(arg, strlen(arg)) == -1)
errExit("sethostname");
/* Retrieve and display hostname */
struct utsname uts;
if (uname(&uts) == -1)
errExit("uname");
printf("uts.nodename in child: %s\n", uts.nodename);
/* Keep the namespace open for a while, by sleeping.
This allows some experimentation--for example, another
process might join the namespace. */
sleep(1000);
return 0; /* Terminates child */
}
#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */
int
main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <child-hostname>\n", argv[0]);
exit(EXIT_SUCCESS);
}
char *stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED)
errExit("mmap");
/* Create a child that has its own UTS namespace;
the child commences execution in childFunc() */
pid_t child_pid = clone(childFunc,
stack + STACK_SIZE, /* Assume stack grows downward */
CLONE_NEWUTS | SIGCHLD, argv[1]);
if (child_pid == -1)
errExit("clone");
printf("PID of child created by clone() is %ld\n", (long) child_pid);
munmap(stack, STACK_SIZE);
/* Parent falls through to here */
sleep(1); /* Give child time to change its hostname */
/* Display the hostname in parent's UTS namespace. This will be
different from the hostname in child's UTS namespace. */
struct utsname uts;
if (uname(&uts) == -1)
errExit("uname");
printf("uts.nodename in parent: %s\n", uts.nodename);
if (waitpid(child_pid, NULL, 0) == -1) /* Wait for child */
errExit("waitpid");
printf("child has terminated\n");
exit(EXIT_SUCCESS);
}
ns_child_exec : 옵션과 명령어를 받아 새로운 namespace에 프로세스를 생성하는 코드#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#ifndef CLONE_NEWCGROUP /* Added in Linux 4.6 */
#define CLONE_NEWCGROUP 0x02000000
#endif
/* A simple error-handling function: print an error message based
on the value in 'errno' and terminate the calling process */
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static void
usage(char *pname)
{
fprintf(stderr, "Usage: %s [options] cmd [arg...]\n", pname);
fprintf(stderr, "Options can be:\n");
fprintf(stderr, " -C new cgroup namespace\n");
fprintf(stderr, " -i new IPC namespace\n");
fprintf(stderr, " -m new mount namespace\n");
fprintf(stderr, " -n new network namespace\n");
fprintf(stderr, " -p new PID namespace\n");
fprintf(stderr, " -u new UTS namespace\n");
fprintf(stderr, " -U new user namespace\n");
fprintf(stderr, " -v Display verbose messages\n");
exit(EXIT_FAILURE);
}
static int /* Start function for cloned child */
childFunc(void *arg)
{
char **argv = arg;
execvp(argv[0], argv);
errExit("execvp");
}
#define STACK_SIZE (1024 * 1024)
int
main(int argc, char *argv[])
{
int flags = 0;
int verbose = 0;
/* Parse command-line options. The initial '+' character in
the final getopt() argument prevents GNU-style permutation
of command-line options. That's useful, since sometimes
the 'command' to be executed by this program itself
has command-line options. We don't want getopt() to treat
those as options to this program. */
int opt;
while ((opt = getopt(argc, argv, "+CimnpuUv")) != -1) {
switch (opt) {
case 'C': flags |= CLONE_NEWCGROUP; break;
case 'i': flags |= CLONE_NEWIPC; break;
case 'm': flags |= CLONE_NEWNS; break;
case 'n': flags |= CLONE_NEWNET; break;
case 'p': flags |= CLONE_NEWPID; break;
case 'u': flags |= CLONE_NEWUTS; break;
case 'U': flags |= CLONE_NEWUSER; break;
case 'v': verbose = 1; break;
default: usage(argv[0]);
}
}
if (optind >= argc)
usage(argv[0]);
char *stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED)
errExit("mmap");
pid_t child_pid = clone(childFunc,
stack + STACK_SIZE,
flags | SIGCHLD, &argv[optind]);
if (child_pid == -1)
errExit("clone");
if (verbose)
printf("%s: PID of child created by clone() is %ld\n",
argv[0], (long) child_pid);
munmap(stack, STACK_SIZE);
/* Parent falls through to here */
if (waitpid(child_pid, NULL, 0) == -1) /* Wait for child */
errExit("waitpid");
if (verbose)
printf("%s: terminating\n", argv[0]);
exit(EXIT_SUCCESS);
}