waitanypid.asm 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. ; vim:ft=fasm:
  2. include 'format/format.inc'
  3. include 'utils.inc'
  4. include 'struct.inc'
  5. format ELF64 executable 3
  6. segment readable writeable
  7. envp dq ?
  8. print_buf.len = 30
  9. print_buf rb print_buf.len
  10. print_buf.end = $
  11. segment readable
  12. nl static_string 10
  13. usage static_string ' <pid> [cmd]', 10,\
  14. 9, 'pid', 9, 'process id to wait for', 10,\
  15. 9, 'cmd', 9, "optionall command to run with '/bin/sh' after <pid> exits", 10
  16. no_prog static_string 'ERROR: failed to get program name (arg0)', 10
  17. ston_failed static_string 'ERROR: failed to convert string to number: "'
  18. ston_failed.end static_string '"', 10
  19. pidfd_open_failed static_string 'ERROR: pidfd_open failed: error code: '
  20. execve_failed static_string 'ERROR: execve failed', 10
  21. bin_sh static_string '/bin/sh', 0
  22. bin_sh.cmd static_string '-c', 0
  23. repeat 1, max:PID_MAX
  24. pid_too_big static_string 'ERROR: pid too big (max is ', `max, ')', 10
  25. end repeat
  26. segment readable executable
  27. include 'stdlib.inc'
  28. entry0:
  29. entry .
  30. prep_args
  31. mov [envp], rdx
  32. main rdi, rsi
  33. exit rax
  34. macro main argc*, argv*
  35. call_args main_impl, argc, argv
  36. end macro
  37. proc main_impl
  38. .prog = r15
  39. .pid = r14
  40. .fd = r13d
  41. .cmd = r12
  42. cmp rdi, 1
  43. jl .no_prog
  44. mov .prog, [rsi + (0 * qword)]
  45. cmp rdi, 2
  46. jl .no_pid
  47. mov .pid, [rsi + (1 * qword)]
  48. mov .cmd, [rsi + (2 * qword)]
  49. cmp rdi, 3
  50. jge .cmd_done
  51. .no_cmd:
  52. xor .cmd, .cmd
  53. .cmd_done:
  54. stonZ u10, .pid
  55. jz .ston_failed
  56. mov .pid, rax
  57. cmp .pid, PID_MAX
  58. jg .pid_too_big
  59. signal SIG.S_HUP, SIG.H_IGN
  60. pidfd_open .pid, 0
  61. mov .fd, eax
  62. cmp .fd, 0
  63. jl .pidfd_open_failed
  64. using_regs rax
  65. stack_frame sizeof.pollfd
  66. .pollfd = stack_frame.use(sizeof.pollfd)
  67. lea rax, [.pollfd]
  68. mov dword [rax + pollfd.fd], .fd
  69. mov word [rax + pollfd.events], pool.IN
  70. mov word [rax + pollfd.revents], 0
  71. ; TODO: add option to wait many pids (any or all)
  72. poll rax, 1, -1
  73. end stack_frame
  74. end using_regs
  75. close rax
  76. test .cmd, .cmd
  77. jnz .run_cmd
  78. xor rax, rax
  79. ret
  80. .run_cmd:
  81. stack_frame (4 * qword)
  82. .args = stack_frame.use(4 * qword)
  83. lea rax, [.args]
  84. mov qword [rax + (0 * qword)], bin_sh
  85. mov qword [rax + (1 * qword)], bin_sh.cmd
  86. mov qword [rax + (2 * qword)], .cmd
  87. mov qword [rax + (3 * qword)], 0
  88. execve bin_sh, rax, [envp]
  89. end stack_frame
  90. ; normally unreachable
  91. write STDERR_FILENO, execve_failed, execve_failed.len
  92. jmp .err
  93. .no_pid:
  94. writeZ STDERR_FILENO, .prog
  95. write STDERR_FILENO, usage, usage.len
  96. xor rax, rax
  97. ret
  98. .pidfd_open_failed:
  99. write STDERR_FILENO, pidfd_open_failed, pidfd_open_failed.len
  100. neg .fd
  101. print i, .fd, print_buf.end
  102. write STDERR_FILENO, rax, rcx
  103. write STDERR_FILENO, nl, nl.len
  104. jmp .err
  105. .pid_too_big:
  106. write STDERR_FILENO, pid_too_big, pid_too_big.len
  107. jmp .err
  108. .ston_failed:
  109. write STDERR_FILENO, ston_failed, ston_failed.len
  110. writeZ STDERR_FILENO, .pid
  111. write STDERR_FILENO, ston_failed.end, ston_failed.end.len
  112. jmp .err
  113. .no_prog:
  114. write STDERR_FILENO, no_prog, no_prog.len
  115. .err:
  116. mov rax, 1
  117. end proc