Skip to content

Instantly share code, notes, and snippets.

@fearful-symmetry
Created July 25, 2022 20:21
Show Gist options
  • Save fearful-symmetry/7c1c005b0e99b961c79e999e55d1a6bb to your computer and use it in GitHub Desktop.
Save fearful-symmetry/7c1c005b0e99b961c79e999e55d1a6bb to your computer and use it in GitHub Desktop.
Test Procargs2 behavior
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