BinaryAnalysisPlatform/bap

the radare2 plugin leaves unterminated processes

ivg opened this issue · 5 comments

ivg commented

It is most likely an issue on the ocaml-radare2 site, and we just probably should stop using it and call radare2 manually. But let's create the issue here, to track it, this is how my ps looks like after a day of work (well after I have noticed that I am running out of the memory),

$ ps ax | grep radare | wc -l
205
$ ps ax | grep radare | head
  301 pts/1    S      0:00 /bin/sh /home/ivg/warehouse/radare2/env.sh /home/ivg/bin/prefix/radare2 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
  308 pts/1    S      0:00 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
  383 pts/1    S      0:00 /bin/sh /home/ivg/warehouse/radare2/env.sh /home/ivg/bin/prefix/radare2 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
  395 pts/1    S      0:00 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
  682 pts/1    S      0:00 /bin/sh /home/ivg/warehouse/radare2/env.sh /home/ivg/bin/prefix/radare2 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
  689 pts/1    S      0:00 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
 2908 pts/1    S      0:00 /bin/sh /home/ivg/warehouse/radare2/env.sh /home/ivg/bin/prefix/radare2 radare2 -2 -q0 testsuite/ko/arm-can-bcm.ko
 2915 pts/1    S      0:00 radare2 -2 -q0 testsuite/ko/arm-can-bcm.ko
 2930 pts/1    S      0:00 /bin/sh /home/ivg/warehouse/radare2/env.sh /home/ivg/bin/prefix/radare2 radare2 -2 -q0 testsuite/ko/arm-can-bcm.ko
 2937 pts/1    S      0:00 radare2 -2 -q0 testsuite/ko/arm-can-bcm.ko

CCint @XVilka

I see that plugins/radare2/radare2_main.ml uses R2.with_command_j which closes the radare2 instance afterwards:

let with_command_j ~cmd f_name =
  let r2 = open_file f_name in
  let output = command ~r2 cmd in
  close r2;
  output |> parse_json

Are you sure there wasn't some failure during calling the command ~r2 cmd? Also what is your radare2 version? Have you tried to open that file from utop with just R2.with_command_j and check if it closes it?

ivg commented

Are you sure there wasn't some failure during calling the command ~r2 cmd?

Yes, I am sure.

Also what is your radare2 version?

$ radare2 -version
radare2 4.5.0-git 24948 @ linux-x86-64 git.4.4.0-429-ga933ba8be
commit: a933ba8bebab7c97b8ffdb56ee8bb5394cfbab2e build: 2020-07-16__11:05:33

Have you tried to open that file from utop with just R2.with_command_j and check if it closes it?

No, but I believe that it won't close.

I think I know what happens. I am using radare2 built from sources, which starts radare2 via a shell script indirection


$ cat `which radare2`
#!/bin/sh
/home/ivg/warehouse/radare2/env.sh '/home/ivg/bin/prefix/radare2' 'radare2' "$@"

We have three processes (generations) for each radare invocation,

  1. the process that executes the radare2 script
  2. the process that executes the env.sh script
  3. the process that finally executes radare2 binary

There could be other descendants if the radare2 process itself spawns more processes. Since ocaml-radare2 just immediately kills the parent process (number 1) with the KILL signal, the two children are left totally unattended. They don't even become zombies (they are sleeping) since their pipes are not exhausted or even closed. The ramifications are pretty tough, we are wasting a lot of precious resources such as file descriptors and memory and the total number of processes.

 1527 pts/1    S      0:00 /bin/sh /home/ivg/warehouse/radare2/env.sh /home/ivg/bin/prefix/radare2 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
 1534 pts/1    S      0:00 radare2 -2 -q0 bin/arm-linux-gnueabi-echo
ivg commented

As a side note, I think we should move this issue to ocaml-radare2.

I am not an expert in shell behaviors, but I believe that we can add exec at least to the radare2 script, to spare one more process. That should be probably done on the radare2 site. Though, of course, there maybe caveats.

Finally, the main issue is the way how the close is handling termination. It should be something more robust and sophisticated. With the KILL signal as the last resort. Just letting radare2 to finish gracefully (by closing the descriptors and waitpiding it, probably with NOWAIT) and only killing radare2 if it doesn't cooperate, would be already enough to resolve this particular issue.

Thoughts?