Advertisement
Guest User

Untitled

a guest
Aug 23rd, 2019
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.02 KB | None | 0 0
  1. use std::io::Read;
  2. use std::io::Write;
  3. use std::time::Duration;
  4. use std::net::{TcpStream, TcpListener};
  5.  
  6. pub fn main() {
  7. // with_bug will panic because split_at splits wrong. without_bug .. works
  8. println!("this works:");
  9. without_bug();
  10. println!("time to do a bug!");
  11. with_bug();
  12. }
  13.  
  14. fn without_bug() {
  15. let cmd = Command::MemoryRead(0x400000, 0x10);
  16. assert_eq!(
  17. cmd.reply_looks_complete("$E01#a6$E01#a6".as_bytes()),
  18. Err(ReplyCategory::Doubled)
  19. );
  20. }
  21.  
  22.  
  23. fn with_bug() {
  24. std::thread::spawn(|| {
  25. let listener = TcpListener::bind("127.0.0.1:1234").unwrap();
  26. let (mut stream, _dest) = listener.accept().unwrap();
  27. stream.write(b"$E01#a6$E01#a6").unwrap();
  28. });
  29. // wait a healthy amount of time for the other thread to start listening
  30. std::thread::sleep(Duration::from_millis(500));
  31. let mut data = [0; 0x1000];
  32. let mut stream = TcpStream::connect("127.0.0.1:1234").unwrap();
  33. // wait for some data Just In Case
  34. std::thread::sleep(Duration::from_millis(500));
  35. stream.read(&mut data).unwrap();
  36. let cmd = Command::MemoryRead(0x400000, 0x10);
  37. assert_eq!(
  38. cmd.reply_looks_complete(&data),
  39. Err(ReplyCategory::Doubled)
  40. );
  41. }
  42.  
  43. fn checksum(s: &[u8]) -> u8 {
  44. s.iter().fold(0, |x, y| x.wrapping_add(*y))
  45. }
  46.  
  47. #[derive(Debug, PartialEq)]
  48. pub enum Command {
  49. MemoryRead(usize, usize),
  50. RegsGet,
  51. }
  52.  
  53. fn check_checksum(buf: &[u8]) -> bool {
  54. if buf.len() < "$#00".len() {
  55. // not even a valid checksum string
  56. return false;
  57. }
  58.  
  59. let checksum_str = &buf[buf.len() - 3..];
  60. if checksum_str[0] != '#' as u8 {
  61. // tail is not #XX
  62. return false;
  63. }
  64.  
  65. let body = &buf[1..][..buf.len() - 4];
  66.  
  67. let checksum = checksum(body);
  68.  
  69. println!("looking for checksum of {:?}: {:02x}", body, checksum);
  70.  
  71. // skip the #
  72. return &checksum_str[1..] == format!("{:02x}", checksum).as_bytes();
  73. }
  74.  
  75. fn is_digit(b: u8) -> bool {
  76. b >= '0' as u8 && b <= '9' as u8
  77. }
  78.  
  79. fn is_err(buf: &[u8]) -> bool {
  80. if buf.len() < b"$EXX#XX".len() {
  81. // not long enough to be an error
  82. return false;
  83. }
  84.  
  85. if buf[0] != '$' as u8 || buf[1] != 'E' as u8 || buf[3] != '#' as u8 {
  86. return false;
  87. }
  88.  
  89. if !check_checksum(&buf[1..=3]) {
  90. return false;
  91. }
  92.  
  93. is_digit(buf[2]) && is_digit(buf[3])
  94. }
  95.  
  96. #[derive(Debug, Clone, Copy, PartialEq)]
  97. enum ReplyCategory {
  98. Doubled,
  99. Incomplete,
  100. }
  101.  
  102. impl Command {
  103. fn reply_looks_complete(&self, buf: &[u8]) -> Result<(), ReplyCategory> {
  104. fn reply_looks_complete_inner(cmd: &Command, buf: &[u8]) -> bool {
  105. println!("checking to see if {} looks complete...", unsafe { std::str::from_utf8_unchecked(buf) });
  106. // test checksum...
  107. match cmd {
  108. Command::MemoryRead(_size, _len) => {
  109. is_err(buf) || check_checksum(buf)
  110. }
  111. Command::RegsGet => {
  112. is_err(buf) || check_checksum(buf)
  113. }
  114. }
  115. }
  116.  
  117. if reply_looks_complete_inner(self, buf) {
  118. Ok(())
  119. } else {
  120. // gdb sometimes goes ahead and sends replies twice.
  121. // specifically observed with `get_regs` and `get_mem`
  122. // requests on `gdbserver localhost:1234 emacs` before the program has been started,
  123. // where gdbserver replies `+$E01#a6$E01#a6`.
  124. //
  125. // i don't know why.
  126. let (low, high) = buf.split_at(buf.len() / 2);
  127. println!(
  128. "half == half? {} == {}",
  129. std::str::from_utf8(low).unwrap(),
  130. std::str::from_utf8(high).unwrap(),
  131. );
  132. if low == high {
  133. println!("not as a full message anyway...");
  134. if reply_looks_complete_inner(self, low) {
  135. Err(ReplyCategory::Doubled)
  136. } else {
  137. Err(ReplyCategory::Incomplete)
  138. }
  139. } else {
  140. Err(ReplyCategory::Incomplete)
  141. }
  142. }
  143. }
  144. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement