- let container_of addr bitoffset =
- if addr <> 0L then (
- let offset = Int64.of_int (bitoffset lsr 3) in
- addr -^ offset
- ) else 0L
- in
-
- (* Do get_task_struct as a recursive subfunction so we don't have
- * to pass around all the fixed arguments on the stack.
- *)
- let rec get_task_struct ~i addr accum =
- if Accum.contains_addr accum addr then accum
- else (
- (* NOTE: The order of the following three statements is crucial
- * to avoid cycles and malicious guests. Do not change it!
- *)
- let bits =
- try Bitstring.bitstring_of_string (get_bytes mem addr (4096*8))
- with Invalid_argument "get_bytes" -> raise (ShapeError i) in
- let accum = Accum.add_address accum addr in
- let accum = ref accum in
-
- if debug then
- eprintf "trying to match task_struct, i=%d %Lx\n%!" i addr;
-
- bitmatch bits with
- | { _ : n1*ws : bitstring; (* Ignore start of task_struct. *)
-
- (* struct list_head tasks *)
- tasks_next : ws : endian(e),
- save_offset_to (offset),
- bind (let addr = container_of tasks_next offset in
- eprintf "offset = %d, tasks_next = %Lx, addr = %Lx\n"
- offset tasks_next addr;
- accum := get_task_struct ~i:1 addr !accum;
- addr);
- tasks_prev : ws : endian(e),
- bind (let addr = container_of tasks_prev offset in
- eprintf "offset = %d, tasks_prev = %Lx, addr = %Lx\n"
- offset tasks_prev addr;
- accum := get_task_struct ~i:1 addr !accum;
- addr);
-
- _ : n2*ws : bitstring;
-
- (* struct task_struct *parent *)
- parent : ws : endian(e),
- bind (let addr = parent in
- accum := get_task_struct ~i:2 addr !accum;
- addr);
-
- (* struct list_head children *)
- children_next : ws : endian(e),
- save_offset_to (offset),
- bind (let addr = container_of children_next offset in
- accum := get_task_struct ~i:2 addr !accum;
- addr);
-
- children_prev : ws : endian(e),
- bind (let addr = container_of children_prev offset in
- accum := get_task_struct ~i:2 addr !accum;
- addr);
-
- (* struct list_head sibling *)
- sibling_next : ws : endian(e),
- save_offset_to (offset),
- bind (let addr = container_of sibling_next offset in
- accum := get_task_struct ~i:2 addr !accum;
- addr);
-
- sibling_prev : ws : endian(e),
- bind (let addr = container_of sibling_prev offset in
- accum := get_task_struct ~i:2 addr !accum;
- addr);
-
- (* struct task_struct *group_leader *)
- group_leader : ws : endian(e),
- bind (let addr = group_leader in
- accum := get_task_struct ~i:2 addr !accum;
- addr)
- } ->
- (* Successful match, so return the updated accumulator. *)
- let accum = !accum in
- let accum = Accum.add_task_struct accum addr { ts_addr = addr } in
- accum
-
- | { _ } ->
- (* Unsuccessful match, throw an exception. *)
- raise (ShapeError (-1))
- )
- in
- get_task_struct ~i:0 addr accum
-
-(* This is the directed search function. *)
-let search debug mem ksymmap =
- let ws = get_wordsize mem in
- let ws = match ws with W32 -> 32 | W64 -> 64 in
- let e = get_endian mem in
- let wse = ws, e in
-
- let init_task =
- try Ksymmap.find "init_task" ksymmap
- with Not_found ->
- eprintf "virt-ps: cannot find kernel symbol 'init_task'\n";
- exit 1 in
-
- let accum = Accum.empty in
-
- let rec loop n1 n2 =
- try
- if debug then eprintf "search: trying (%d, %d)\n" n1 n2;
- let ts = get_task_struct debug mem wse (n1, n2) init_task accum in
- if debug then eprintf "search: success (%d, %d)\n" n1 n2;
- ts
- with
- | ShapeError ((-1|0|1) as i) ->
- if debug then eprintf "search: ShapeError %d\n" i;
- loop (n1+1) n2
- | ShapeError 2 ->
- if debug then eprintf "search: ShapeError 2\n";
- loop n1 (n2+1)
- in
- let ts = loop 0 0 in
- ()
-
-let run debug ({ mem = mem }, ksymmap, _) =
- search debug mem ksymmap