clone_shim #1
6
.ocamlformat
Normal file
6
.ocamlformat
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
profile = ocamlformat
|
||||||
|
break-cases = fit
|
||||||
|
margin = 77
|
||||||
|
parse-docstrings = true
|
||||||
|
wrap-comments = true
|
||||||
|
line-endings = lf
|
17
.vscode/c_cpp_properties.json
vendored
Normal file
17
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"/home/jsh77/.opam/default/lib/ocaml"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/usr/bin/gcc",
|
||||||
|
"cStandard": "gnu17",
|
||||||
|
"cppStandard": "gnu++14",
|
||||||
|
"intelliSenseMode": "linux-gcc-x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
10
tools/clone/Makefile
Normal file
10
tools/clone/Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
all: clone_shim
|
||||||
|
|
||||||
|
clone_shim: clone_shim.ml clone3_stub.o
|
||||||
|
ocamlc -custom -o clone_shim clone_shim.ml clone3_stub.o
|
||||||
|
|
||||||
|
clone3_stub.o: clone3_stub.c
|
||||||
|
ocamlc -c clone3_stub.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm clone_shim.cmi clone_shim.cmo clone3_stub.o
|
219
tools/clone/clone3_stub.c
Normal file
219
tools/clone/clone3_stub.c
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
#define CAML_NAME_SPACE
|
||||||
|
#include <caml/mlvalues.h>
|
||||||
|
#include <caml/memory.h>
|
||||||
|
#include <caml/callback.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
|
#ifndef CLONE_NEWCGROUP /* Added in Linux 4.6 */
|
||||||
|
#define CLONE_NEWCGROUP 0x02000000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLONE_CLEAR_SIGHAND /* Added in Linux 5.5 */
|
||||||
|
#define CLONE_CLEAR_SIGHAND 0x100000000ULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLONE_NEWTIME /* Added in Linux 5.6 */
|
||||||
|
#define CLONE_NEWTIME 0x00000080
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
type clone_flag =
|
||||||
|
| CLONE_CHILD_CLEARTID
|
||||||
|
| CLONE_CHILD_SETTID
|
||||||
|
| CLONE_CLEAR_SIGHAND
|
||||||
|
| CLONE_FILES
|
||||||
|
| CLONE_FS
|
||||||
|
| CLONE_IO
|
||||||
|
| CLONE_NEWCGROUP
|
||||||
|
| CLONE_NEWIPC
|
||||||
|
| CLONE_NEWNET
|
||||||
|
| CLONE_NEWNS
|
||||||
|
| CLONE_NEWPID
|
||||||
|
| CLONE_NEWUSER
|
||||||
|
| CLONE_NEWUTS
|
||||||
|
| CLONE_PARENT
|
||||||
|
| CLONE_PARENT_SETTID
|
||||||
|
| CLONE_PIDFD
|
||||||
|
| CLONE_PTRACE
|
||||||
|
| CLONE_SETTLS
|
||||||
|
| CLONE_SIGHAND
|
||||||
|
| CLONE_SYSVSEM
|
||||||
|
| CLONE_THREAD
|
||||||
|
| CLONE_UNTRACED
|
||||||
|
| CLONE_VFORK
|
||||||
|
| CLONE_VM
|
||||||
|
| CLONE_NEWTIME
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned long long caml_clone_flag(value val)
|
||||||
|
{
|
||||||
|
switch (Long_val(val))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return CLONE_CHILD_CLEARTID;
|
||||||
|
case 1:
|
||||||
|
return CLONE_CHILD_SETTID;
|
||||||
|
case 2:
|
||||||
|
return CLONE_CLEAR_SIGHAND;
|
||||||
|
case 3:
|
||||||
|
return CLONE_FILES;
|
||||||
|
case 4:
|
||||||
|
return CLONE_FS;
|
||||||
|
case 5:
|
||||||
|
return CLONE_IO;
|
||||||
|
case 6:
|
||||||
|
return CLONE_NEWCGROUP;
|
||||||
|
case 7:
|
||||||
|
return CLONE_NEWIPC;
|
||||||
|
case 8:
|
||||||
|
return CLONE_NEWNET;
|
||||||
|
case 9:
|
||||||
|
return CLONE_NEWNS;
|
||||||
|
case 10:
|
||||||
|
return CLONE_NEWPID;
|
||||||
|
case 11:
|
||||||
|
return CLONE_NEWUSER;
|
||||||
|
case 12:
|
||||||
|
return CLONE_NEWUTS;
|
||||||
|
case 13:
|
||||||
|
return CLONE_PARENT;
|
||||||
|
case 14:
|
||||||
|
return CLONE_PARENT_SETTID;
|
||||||
|
case 15:
|
||||||
|
return CLONE_PIDFD;
|
||||||
|
case 16:
|
||||||
|
return CLONE_PTRACE;
|
||||||
|
case 17:
|
||||||
|
return CLONE_SETTLS;
|
||||||
|
case 18:
|
||||||
|
return CLONE_SIGHAND;
|
||||||
|
case 19:
|
||||||
|
return CLONE_SYSVSEM;
|
||||||
|
case 20:
|
||||||
|
return CLONE_THREAD;
|
||||||
|
case 21:
|
||||||
|
return CLONE_UNTRACED;
|
||||||
|
case 22:
|
||||||
|
return CLONE_VFORK;
|
||||||
|
case 23:
|
||||||
|
return CLONE_VM;
|
||||||
|
case 24:
|
||||||
|
return CLONE_NEWTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
type clone_args =
|
||||||
|
{ flags: int (** Flags for the clone call *)
|
||||||
|
; pidfd: pid_t ref option (** Pointer to where to store the pidfd *)
|
||||||
|
; child_tid: pid_t ref option
|
||||||
|
(** Where to place the child thread ID in the child's memory *)
|
||||||
|
; parent_tid: pid_t ref option
|
||||||
|
(** Where to place the child thread ID in the parent's memory *)
|
||||||
|
; exit_signal: int
|
||||||
|
(** Signal to deliver to parent on child's termination *)
|
||||||
|
; stack: bytes ref option
|
||||||
|
(** Stack for the child if the parent and child share memory *)
|
||||||
|
; tls: int ref option (** Location of new thread local storage *)
|
||||||
|
; set_tid: pid_t list option
|
||||||
|
(** Optional list of specific pids for one or more of the namespaces *)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
value caml_clone3(value caml_cl_args, value fn)
|
||||||
|
{
|
||||||
|
CAMLparam2(caml_cl_args, fn);
|
||||||
|
|
||||||
|
// extract arguments
|
||||||
|
unsigned long long flags = 0;
|
||||||
|
|
||||||
|
value tail = Field(caml_cl_args, 0);
|
||||||
|
while (!Is_none(tail))
|
||||||
|
{
|
||||||
|
flags |= caml_clone_flag(Field(tail, 0));
|
||||||
|
tail = Field(tail, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pidfd; // output
|
||||||
|
pid_t child_tid; // output
|
||||||
|
pid_t parent_tid; // output
|
||||||
|
int exit_signal; // input
|
||||||
|
void *stack; // input
|
||||||
|
size_t stack_size; // input
|
||||||
|
void *tls; // input
|
||||||
|
pid_t *set_tid; // input
|
||||||
|
size_t set_tid_size; // input
|
||||||
|
int cgroup; // input
|
||||||
|
|
||||||
|
exit_signal = Int_val(Field(caml_cl_args, 4));
|
||||||
|
|
||||||
|
value stack_val = Field(caml_cl_args, 5);
|
||||||
|
if (Is_some(stack_val))
|
||||||
|
{
|
||||||
|
stack = Bytes_val(Some_val(stack_val));
|
||||||
|
stack_size = caml_string_length(Some_val(stack_val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack = NULL;
|
||||||
|
stack_size = 0;
|
||||||
|
}
|
||||||
|
// TODO: set_tid
|
||||||
|
|
||||||
|
struct clone_args cl_args = {
|
||||||
|
.flags = (uint64_t)flags,
|
||||||
|
.pidfd = (uint64_t)&pidfd,
|
||||||
|
.child_tid = (uint64_t)&child_tid,
|
||||||
|
.parent_tid = (uint64_t)&parent_tid,
|
||||||
|
.exit_signal = (uint64_t)exit_signal,
|
||||||
|
.stack = (uint64_t)stack,
|
||||||
|
.stack_size = (uint64_t)stack_size,
|
||||||
|
.tls = (uint64_t)0,
|
||||||
|
// .set_tid = set_tid,
|
||||||
|
// .set_tid_size = set_tid_size,
|
||||||
|
// .cgroup = cgroup,
|
||||||
|
};
|
||||||
|
|
||||||
|
// clone
|
||||||
|
pid_t clone_result = syscall(SYS_clone3, &cl_args, sizeof(struct clone_args));
|
||||||
|
if (clone_result == 0)
|
||||||
|
{
|
||||||
|
// run the callback
|
||||||
|
// value v = caml_callback(fn, Val_none);
|
||||||
|
// if (Is_exception_result(v))
|
||||||
|
// {
|
||||||
|
// exit(1);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// exit(0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
char *newargv[] = {"/bin/sh", NULL};
|
||||||
|
char *newenviron[] = {NULL};
|
||||||
|
|
||||||
|
execve(newargv[0], newargv, newenviron);
|
||||||
|
perror("execve");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (clone_result < 0)
|
||||||
|
{
|
||||||
|
// handle error
|
||||||
|
perror("clone");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write back results to caml refs
|
||||||
|
if (Is_some(Field(caml_cl_args, 1)))
|
||||||
|
{
|
||||||
|
Store_field(caml_cl_args, 1, Val_int(pidfd));
|
||||||
|
}
|
||||||
|
|
||||||
|
CAMLreturn(Val_int(clone_result));
|
||||||
|
}
|
BIN
tools/clone/clone_shim
Executable file
BIN
tools/clone/clone_shim
Executable file
Binary file not shown.
124
tools/clone/clone_shim.ml
Normal file
124
tools/clone/clone_shim.ml
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
let usage_msg = "clone [options] [program [arguments]]"
|
||||||
|
|
||||||
|
let ipc = ref false
|
||||||
|
|
||||||
|
let mount = ref false
|
||||||
|
|
||||||
|
let network = ref false
|
||||||
|
|
||||||
|
let pid = ref false
|
||||||
|
|
||||||
|
let uts = ref false
|
||||||
|
|
||||||
|
let user = ref false
|
||||||
|
|
||||||
|
let cgroup = ref false
|
||||||
|
|
||||||
|
let time = ref false
|
||||||
|
|
||||||
|
let verbose = ref false
|
||||||
|
|
||||||
|
let program_args = ref []
|
||||||
|
|
||||||
|
let anon_fun arg = program_args := arg :: !program_args
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[ ("-i", Arg.Set ipc, "Clone into a new IPC namespace")
|
||||||
|
; ("-m", Arg.Set mount, "Clone into a new mount namespace")
|
||||||
|
; ("-n", Arg.Set network, "Clone into a new network namespace")
|
||||||
|
; ("-p", Arg.Set pid, "Clone into a new PID namespace")
|
||||||
|
; ("-u", Arg.Set uts, "Clone into a new UTS (Unix Time Sharing) namespace")
|
||||||
|
; ("-U", Arg.Set user, "Clone into a new user namespace")
|
||||||
|
; ("-C", Arg.Set cgroup, "Clone into a new IPC namespace")
|
||||||
|
; ("-T", Arg.Set time, "Clone into a new time namespace")
|
||||||
|
; ("-v", Arg.Set verbose, "Verbose logging") ]
|
||||||
|
|
||||||
|
let veprintf = if !verbose then Printf.eprintf else Printf.eprintf
|
||||||
|
|
||||||
|
type pid_t = int
|
||||||
|
|
||||||
|
type clone_flag =
|
||||||
|
| CLONE_CHILD_CLEARTID
|
||||||
|
| CLONE_CHILD_SETTID
|
||||||
|
| CLONE_CLEAR_SIGHAND
|
||||||
|
| CLONE_FILES
|
||||||
|
| CLONE_FS
|
||||||
|
| CLONE_IO
|
||||||
|
| CLONE_NEWCGROUP
|
||||||
|
| CLONE_NEWIPC
|
||||||
|
| CLONE_NEWNET
|
||||||
|
| CLONE_NEWNS
|
||||||
|
| CLONE_NEWPID
|
||||||
|
| CLONE_NEWUSER
|
||||||
|
| CLONE_NEWUTS
|
||||||
|
| CLONE_PARENT
|
||||||
|
| CLONE_PARENT_SETTID
|
||||||
|
| CLONE_PIDFD
|
||||||
|
| CLONE_PTRACE
|
||||||
|
| CLONE_SETTLS
|
||||||
|
| CLONE_SIGHAND
|
||||||
|
| CLONE_SYSVSEM
|
||||||
|
| CLONE_THREAD
|
||||||
|
| CLONE_UNTRACED
|
||||||
|
| CLONE_VFORK
|
||||||
|
| CLONE_VM
|
||||||
|
| CLONE_NEWTIME
|
||||||
|
|
||||||
|
type clone_args =
|
||||||
|
{ flags: clone_flag list (** Flags for the clone call *)
|
||||||
|
; pidfd: pid_t ref option (** Pointer to where to store the pidfd *)
|
||||||
|
; child_tid: pid_t ref option
|
||||||
|
(** Where to place the child thread ID in the child's memory *)
|
||||||
|
; parent_tid: pid_t ref option
|
||||||
|
(** Where to place the child thread ID in the parent's memory *)
|
||||||
|
; exit_signal: int
|
||||||
|
(** Signal to deliver to parent on child's termination *)
|
||||||
|
; stack: bytes ref option
|
||||||
|
(** Stack for the child if the parent and child share memory *)
|
||||||
|
; tls: int ref option (** Location of new thread local storage *)
|
||||||
|
; set_tid: pid_t list option
|
||||||
|
(** Optional list of specific pids for one or more of the namespaces *)
|
||||||
|
}
|
||||||
|
|
||||||
|
external clone3 : clone_args -> (unit -> unit) -> unit = "caml_clone3"
|
||||||
|
|
||||||
|
let hello_world_caml unit = Printf.eprintf "hello world from ocaml\n"
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let flags = ref [] in
|
||||||
|
Arg.parse speclist anon_fun usage_msg ;
|
||||||
|
if !ipc then (
|
||||||
|
veprintf "cloning into a new IPC namespace\n" ;
|
||||||
|
flags := CLONE_NEWIPC :: !flags ) ;
|
||||||
|
if !mount then (
|
||||||
|
veprintf "cloning into a new mount namespace\n" ;
|
||||||
|
flags := CLONE_NEWNS :: !flags ) ;
|
||||||
|
if !network then (
|
||||||
|
veprintf "cloning into a new network namespace\n" ;
|
||||||
|
flags := CLONE_NEWNET :: !flags ) ;
|
||||||
|
if !pid then (
|
||||||
|
veprintf "cloning into a new PID namespace\n" ;
|
||||||
|
flags := CLONE_NEWPID :: !flags ) ;
|
||||||
|
if !uts then (
|
||||||
|
veprintf "cloning into a new UTS namespace\n" ;
|
||||||
|
flags := CLONE_NEWUTS :: !flags ) ;
|
||||||
|
if !user then (
|
||||||
|
veprintf "cloning into a new user namespace\n" ;
|
||||||
|
flags := CLONE_NEWUSER :: !flags ) ;
|
||||||
|
if !cgroup then (
|
||||||
|
veprintf "cloning into a new cgroup namespace\n" ;
|
||||||
|
flags := CLONE_NEWCGROUP :: !flags ) ;
|
||||||
|
if !time then (
|
||||||
|
veprintf "cloning into a new time namespace\n" ;
|
||||||
|
flags := CLONE_NEWTIME :: !flags ) ;
|
||||||
|
clone3
|
||||||
|
{ flags= !flags
|
||||||
|
; pidfd= None
|
||||||
|
; child_tid= None
|
||||||
|
; parent_tid= None
|
||||||
|
; exit_signal= 0
|
||||||
|
; stack= None
|
||||||
|
; tls= None
|
||||||
|
; set_tid= None }
|
||||||
|
hello_world_caml ;
|
||||||
|
veprintf "exiting now\n"
|
Reference in New Issue
Block a user