Created
July 31, 2022 10:39
-
-
Save musaprg/e94f89f54252fbaa2b8116475640ceeb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const os = std.os; | |
const fs = std.fs; | |
const fmt = std.fmt; | |
const heap = std.heap; | |
const ArenaAllocator = heap.ArenaAllocator; | |
const linux = os.linux; | |
const print = std.debug.print; | |
// no interface natively in zig for now | |
// imported from https://github.com/ziglang/zig/blob/0.9.x/lib/libc/include/any-linux-any/linux/capability.h | |
const CAP_SETGID = 6; | |
const CAP_SETUID = 7; | |
const _LINUX_CAPABILITY_VERSION_3 = 0x20080522; | |
const _LINUX_CAPABILITY_U32S_3 = 2; | |
fn parent(cpid: os.pid_t) !void { | |
print("parent pid: {}\n", .{linux.getpid()}); | |
print("child pid: {}\n", .{cpid}); | |
var result = os.waitpid(cpid, 0); // i'm not sure how to handle WaitPidResult.status with zig, there's no macro like WIFEXITED | |
_ = result.status; | |
} | |
fn child(allocator: std.mem.Allocator) !void { | |
const flags = linux.CLONE.NEWIPC | linux.CLONE.NEWNET | linux.CLONE.NEWUSER; | |
if (linux.unshare(flags) == -1) { | |
print("unshare failed\n", .{}); | |
os.exit(1); | |
} | |
// Get current capabilities | |
var chdrp = try allocator.create(linux.cap_user_header_t); | |
var cdatap = try allocator.create(linux.cap_user_data_t); | |
if (linux.capget(chdrp, cdatap) == -1) { | |
print("capget failed\n", .{}); | |
os.exit(1); | |
} | |
// https://man7.org/linux/man-pages/man7/capabilities.7.html | |
// Set CAP_SETGID and CAP_SETUID | |
var hdrp = linux.cap_user_header_t{ | |
.version = _LINUX_CAPABILITY_VERSION_3, | |
.pid = 0, | |
}; | |
var datap = linux.cap_user_data_t{ | |
.effective = cdatap.effective | CAP_SETGID | CAP_SETUID, | |
.permitted = cdatap.permitted | CAP_SETGID | CAP_SETUID, | |
.inheritable = cdatap.inheritable | CAP_SETGID | CAP_SETUID, | |
}; | |
if (linux.capset(&hdrp, &datap) == -1) { | |
print("capset failed\n", .{}); | |
os.exit(1); | |
} | |
_ = allocator; | |
var uid = linux.getuid(); | |
var gid = linux.getgid(); | |
print("uid: {}\n", .{uid}); | |
print("gid: {}\n", .{gid}); | |
var pid = linux.getpid(); | |
var string_pid = try fmt.allocPrint(allocator, "{}", .{pid}); | |
defer allocator.free(string_pid); | |
//var uid_map_path = fs.path.join(allocator, &[_][]const u8{ "/proc", string_pid, "uid_map" }) catch unreachable; | |
//var gid_map_path = fs.path.join(allocator, &[_][]const u8{ "/proc", string_pid, "gid_map" }) catch unreachable; | |
var uid_map_path = fs.path.join(allocator, &[_][]const u8{ "/proc", "self", "uid_map" }) catch unreachable; | |
var gid_map_path = fs.path.join(allocator, &[_][]const u8{ "/proc", "self", "gid_map" }) catch unreachable; | |
print("uid_map_path: {s}\n", .{uid_map_path}); | |
print("gid_map_path: {s}\n", .{gid_map_path}); | |
var uid_map = try fs.openFileAbsolute(uid_map_path, .{ .write = true }); | |
defer uid_map.close(); | |
var gid_map = try fs.openFileAbsolute(gid_map_path, .{ .write = true }); | |
defer gid_map.close(); | |
var uid_map_contents = try fmt.allocPrint(allocator, "0 {} 1", .{uid}); | |
defer allocator.free(uid_map_contents); | |
var gid_map_contents = try fmt.allocPrint(allocator, "0 {} 1", .{gid}); | |
defer allocator.free(gid_map_contents); | |
try uid_map.writer().writeAll(uid_map_contents); | |
try gid_map.writer().writeAll(gid_map_contents); | |
const child_args = [_:null]?[*:0]const u8{ "/bin/sh", null }; | |
const envp = [_:null]?[*:0]const u8{null}; | |
try os.execveZ("/bin/sh", &child_args, &envp) catch return; | |
} | |
// Use fork and unshare to create a new process with a new PID | |
// youki: https://github.com/containers/youki/blob/619ae7d1eccbd82fd116465ed25ef410ace2a2a1/crates/libcontainer/src/process/container_main_process.rs#L206-L240 | |
pub fn main() !void { | |
var arena = ArenaAllocator.init(std.heap.page_allocator); | |
defer arena.deinit(); | |
const allocator = arena.allocator(); | |
var pid = os.fork() catch { | |
print("fork failed\n", .{}); | |
os.exit(1); | |
}; | |
if (pid == 0) { // child | |
try child(allocator); | |
} else { // parent | |
try parent(pid); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment