Created
July 25, 2022 20:21
-
-
Save fearful-symmetry/7c1c005b0e99b961c79e999e55d1a6bb to your computer and use it in GitHub Desktop.
Test Procargs2 behavior
This file contains hidden or 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
package main | |
/* | |
#include <stdlib.h> | |
#include <sys/sysctl.h> | |
#include <sys/mount.h> | |
#include <mach/mach_init.h> | |
#include <mach/mach_host.h> | |
#include <mach/host_info.h> | |
#include <libproc.h> | |
#include <mach/processor_info.h> | |
#include <mach/vm_map.h> | |
*/ | |
import "C" | |
import ( | |
"bytes" | |
"encoding/binary" | |
"fmt" | |
"io" | |
"os" | |
"strconv" | |
"syscall" | |
"unsafe" | |
) | |
func main() { | |
pid := os.Getpid() | |
// ==== Get const values | |
argmax, err := argmaxVal() | |
if err != nil { | |
fmt.Printf("error in KERN_ARGMAX:") | |
return | |
} | |
fmt.Printf("KERN_ARGMAX: %d\n", argmax) | |
fmt.Printf(" ARG_MAX: %d\n", C.ARG_MAX) | |
fmt.Println() | |
// ==== Get Self Pid info | |
size, resp, err := getProcArgs(pid) | |
if err != nil { | |
fmt.Printf("error in getProcArgs: %s for pid %d\n", err, pid) | |
return | |
} | |
args, exe, err := readArgsBuf(resp, size) | |
if err != nil { | |
fmt.Printf("error in readArgsBuf: %s for pid %d\n", err, pid) | |
return | |
} | |
fmt.Printf("pid %d is %s, args: %v\n", pid, exe, args) | |
if len(os.Args) < 2 { | |
return | |
} | |
fmt.Println() | |
// === Try a user-supplied PID | |
argStr := os.Args[1] | |
userPid, err := strconv.ParseInt(argStr, 10, 64) | |
if err != nil { | |
fmt.Printf("error in ParseInt: %s\n", err) | |
return | |
} | |
size, resp, err = getProcArgs(int(userPid)) | |
if err != nil { | |
fmt.Printf("error in getProcArgs: %s for pid %d\n", err, pid) | |
return | |
} | |
args, exe, err = readArgsBuf(resp, size) | |
if err != nil { | |
fmt.Printf("error in readArgsBuf: %s for pid %d\n", err, pid) | |
return | |
} | |
fmt.Printf("pid %d is %s, args: %v\n", pid, exe, args) | |
} | |
func argmaxVal() (int, error) { | |
var argmax C.size_t | |
mib := []C.int{C.CTL_KERN, C.KERN_ARGMAX} | |
sizeof := unsafe.Sizeof(argmax) | |
err := sysctl2(mib, uintptr(unsafe.Pointer(&argmax)), uintptr(unsafe.Pointer(&sizeof)), nil, 0) | |
return int(argmax), err | |
} | |
func getProcArgs(pid int) (int, []byte, error) { | |
mib := []C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)} | |
argmax := uintptr(C.ARG_MAX) | |
buf := make([]byte, argmax) | |
//try to catch the buffer size | |
var sizeNeeded C.size_t | |
err := sysctl2(mib, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(&sizeNeeded)), nil, 0) | |
if err != nil { | |
return 0, nil, fmt.Errorf("error in nil-oldp sysctl: %w", err) | |
} | |
fmt.Printf("KERN_PROCARGS2 for PID %d buffer size reported: %d\n", pid, sizeNeeded) | |
err = sysctl2(mib, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&argmax)), nil, 0) | |
if err != nil { | |
return 0, nil, fmt.Errorf("error in sysctl for KERN_PROCARGS2: %w", err) | |
} | |
return int(sizeNeeded), buf, nil | |
} | |
func readArgsBuf(in []byte, argmax int) ([]string, string, error) { | |
bbuf := bytes.NewBuffer(in) | |
bbuf.Truncate(argmax) | |
var argc int32 // raw buffer | |
_ = binary.Read(bbuf, binary.LittleEndian, &argc) // read length | |
path, err := bbuf.ReadBytes(0) | |
if err != nil { | |
return nil, "", fmt.Errorf("error reading the executable name: %w", err) | |
} | |
exeName := stripNullByte(path) | |
// skip trailing nul bytes | |
for { | |
c, err := bbuf.ReadByte() | |
if err != nil { | |
return nil, "", fmt.Errorf("error skipping null values in KERN_PROCARGS2 buffer: %w", err) | |
} | |
if c != 0 { | |
_ = bbuf.UnreadByte() | |
break | |
} | |
} | |
// read CLI args | |
var argv []string | |
for i := 0; i < int(argc); i++ { | |
arg, err := bbuf.ReadBytes(0) | |
if err == io.EOF { | |
break | |
} | |
if err != nil { | |
return nil, exeName, fmt.Errorf("error reading args from KERN_PROCARGS2: %w", err) | |
} | |
argv = append(argv, stripNullByte(arg)) | |
} | |
return argv, exeName, nil | |
} | |
func stripNullByte(buf []byte) string { | |
return string(buf[0 : len(buf)-1]) | |
} | |
func stripNullByteRaw(buf []byte) []byte { | |
return buf[0 : len(buf)-1] | |
} | |
func sysctl2(mib []C.int, old uintptr, oldlen uintptr, | |
new *byte, newlen uintptr) (err error) { | |
p0 := unsafe.Pointer(&mib[0]) | |
_, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p0), | |
uintptr(len(mib)), | |
old, oldlen, | |
uintptr(unsafe.Pointer(new)), newlen) | |
if e1 != 0 { | |
err = e1 | |
} | |
return err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment