Skip to content

Instantly share code, notes, and snippets.

@ducktype
Last active November 27, 2018 19:31
Show Gist options
  • Save ducktype/fe1d67ed5ad1e79cc6f058566ee8f680 to your computer and use it in GitHub Desktop.
Save ducktype/fe1d67ed5ad1e79cc6f058566ee8f680 to your computer and use it in GitHub Desktop.
//NOTE: we need to change this cast in: zig/lib/zig/std/os/linux/index.twig
//pub fn geteuid() u32 {
// return @intCast(u32,syscall0(SYS_geteuid));
//}
//
//pub fn getegid() u32 {
// return @intCast(u32,syscall0(SYS_getegid));
//}
//pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: ?[*]const u8, flags: u32, data: usize) usize {
// return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
//}
//TODO: avoid Dir.scan multiple times
const std = @import("std");
const allocator = std.debug.global_allocator;
//const allocator = std.heap.c_allocator; //requires C compiler installed to build?
pub fn main() !void {
//var args = std.os.args();
var stdout = &(try std.io.getStdOut()).outStream().stream;
var ex_dir = try std.os.selfExeDirPathAlloc(allocator);
var app_rootdir = try std.os.path.join(allocator,ex_dir,"approot");
var ofs_dir = try std.os.path.join(allocator,ex_dir,"ofs");
try stdout.print("start!\n");
try stdout.print("ex_dir = {}\n",ex_dir);
try stdout.print("app_rootdir = {}\n",app_rootdir);
try stdout.print("ofs_dir = {}\n",ofs_dir);
//get euid/egid
var real_euid = @intCast(u32,std.os.linux.geteuid());
try stdout.print("euid: {}\n",real_euid);
var real_egid = @intCast(u32,std.os.linux.getegid());
try stdout.print("egid: {}\n",real_egid);
//set process dumpable
//std.os.linux.syscall5(std.os.linux.SYS_prctl,PR_SET_DUMPABLE, 1, 0, 0, 0);
//var retd = std.os.linux.syscall5(std.os.linux.SYS_prctl,4,1,0,0,0);
//try stdout.print("dumpable: {}\n",retd);
//unshare current process
var ret = std.os.linux.unshare(std.os.linux.CLONE_NEWUSER|std.os.linux.CLONE_NEWNS|std.os.linux.CLONE_NEWPID);
try stdout.print("unshare: {}\n",ret);
//map uid/gid to root
var pssg = "/proc/self/setgroups";
var psum = "/proc/self/uid_map";
var psgm = "/proc/self/gid_map";
var pssg_value = "deny";
var psum_value = try std.fmt.allocPrint(allocator,"0 {} 1",real_euid);
var psgm_value = try std.fmt.allocPrint(allocator,"0 {} 1",real_egid);
try std.io.writeFile(pssg,pssg_value);
try stdout.print("setgroups: {}\n",pssg_value);
try std.io.writeFile(psum,psum_value);
try stdout.print("uid_map: {}\n",psum_value);
try std.io.writeFile(psgm,psgm_value);
try stdout.print("gid_map: {}\n",psgm_value);
//set root propagation
//ret = std.os.linux.mount(c"none",c"/",@intToPtr([*]const u8,0),std.os.linux.MS_REC|std.os.linux.MS_PRIVATE,0);
ret = std.os.linux.mount(c"none",c"/",null,std.os.linux.MS_REC|std.os.linux.MS_PRIVATE,0);
try stdout.print("make root private: {}\n",ret);
//mount overlayfs merge
var dir = try std.os.Dir.open(allocator,app_rootdir);
defer dir.close();
while (try dir.next()) |entry| {
if(entry.kind!=std.os.Dir.Entry.Kind.Directory){
continue;
}
var dir_name = entry.name;
var overlay_lower = try std.fmt.allocPrint(allocator,"/{}",dir_name);
var overlay_upper = try std.os.path.join(allocator,app_rootdir,dir_name);
var overlay_merge = try std.os.path.join(allocator,ofs_dir,dir_name);
var overlay_work = try std.fmt.allocPrint(allocator,"{}.work",overlay_merge);
try std.os.makePath(allocator,overlay_merge);
try std.os.makePath(allocator,overlay_work);
var mount_options = try std.fmt.allocPrint(allocator,"lowerdir={},upperdir={},workdir={}",overlay_lower,overlay_upper,overlay_work);
const c_overlay_merge = try std.cstr.addNullByte(allocator,overlay_merge);
const c_mount_options = try std.cstr.addNullByte(allocator,mount_options);
ret = std.os.linux.mount(c"none",c_overlay_merge.ptr,c"overlay",0,@ptrToInt(c_mount_options.ptr));
try stdout.print("mount ofs: {} {} {}\n",entry.name,overlay_merge,mount_options);
try stdout.print("ret: {}\n",ret);
}
//mount bind overlayfs merge
var dir2 = try std.os.Dir.open(allocator,app_rootdir);
defer dir2.close();
while (try dir2.next()) |entry| {
if(entry.kind!=std.os.Dir.Entry.Kind.Directory){
continue;
}
var dir_name = entry.name;
var mount_bind = try std.fmt.allocPrint(allocator,"/{}",dir_name);
var mount_merge = try std.os.path.join(allocator,ofs_dir,dir_name);
const c_mount_merge = try std.cstr.addNullByte(allocator,mount_merge);
const c_mount_bind = try std.cstr.addNullByte(allocator,mount_bind);
var ret2 = std.os.linux.mount(c_mount_merge.ptr,c_mount_bind.ptr,c"bind",std.os.linux.MS_BIND,0);
try stdout.print("mount bind: {} {} {}\n",entry.name,mount_merge,mount_bind);
try stdout.print("ret: {}\n",ret2);
//var ret3 = std.os.linux.mount(c"none",c_mount_bind.ptr,@intToPtr([*]const u8,0),std.os.linux.MS_PRIVATE,0);
var ret3 = std.os.linux.mount(c"none",c_mount_bind.ptr,null,std.os.linux.MS_PRIVATE,0);
try stdout.print("mount bind private: {} {}\n",entry.name,mount_bind);
try stdout.print("ret: {}\n",ret3);
}
//exec command (default to busybox)
var shell_path = try std.os.path.join(allocator,ex_dir,"sash");
var exec_argv = ([][]u8{shell_path})[0..];
var exec_envs = std.BufMap.init(allocator);
try exec_envs.set("PS1","-[alone]- # ");
//const child = std.os.ChildProcess.init(exec_argv,allocator) catch unreachable;
//child.env_map = &exec_envs;
//defer child.deinit();
//var first_arg = args.next(allocator);
//var second_arg = args.next(allocator);
//var first_arg = args.nextPosix();
//var second_arg = args.nextPosix();
var args = try std.os.argsAlloc(allocator);
defer std.os.argsFree(allocator,args);
if(args.len>1){
//TODO: convert ArgIterator to []const []const u8
//exec_argv = []const []const u8 {second_arg.?};
exec_argv = args[1..];
exec_envs = std.BufMap.init(allocator);
}
try stdout.print("exec: {}\n",exec_argv[0]);
//std.os.linux.execve(exec_argv0,exec_args,exec_envs);
//try child.spawn();
var ret_exec = std.os.posixExecve(exec_argv, &exec_envs, allocator);
try stdout.print("ret: {}\n",ret_exec);
//findmnt -R -o SOURCE,FSROOT,TARGET,MAJ:MIN,FSTYPE,PROPAGATION,OPTIONS
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment