panwrap-util.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * © Copyright 2017 The BiOpenly Community
  3. *
  4. * This program is free software and is provided to you under the terms of the
  5. * GNU General Public License version 2 as published by the Free Software
  6. * Foundation, and any use by you of this program is subject to the terms
  7. * of such GNU licence.
  8. *
  9. * A copy of the licence is included with the program, and can also be obtained
  10. * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  11. * Boston, MA 02110-1301, USA.
  12. *
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdbool.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <time.h>
  21. #include <ctype.h>
  22. #include "panwrap.h"
  23. #define HEXDUMP_COL_LEN 4
  24. #define HEXDUMP_ROW_LEN 16
  25. static bool enable_timestamps = false,
  26. enable_hexdump_trimming = true;
  27. static bool time_is_frozen = false;
  28. static struct timespec start_time;
  29. static struct timespec total_time_frozen, start_freeze_time, frozen_timestamp;
  30. static FILE *log_output;
  31. FILE *ioctl_fp;
  32. void
  33. panwrap_log_decoded_flags(const struct panwrap_flag_info *flag_info,
  34. u64 flags)
  35. {
  36. bool decodable_flags_found = false;
  37. panwrap_log_cont("0x%llx", flags);
  38. for (int i = 0; flag_info[i].name; i++) {
  39. if ((flags & flag_info[i].flag) != flag_info[i].flag)
  40. continue;
  41. if (!decodable_flags_found) {
  42. decodable_flags_found = true;
  43. panwrap_log_cont(" (");
  44. } else {
  45. panwrap_log_cont(" | ");
  46. }
  47. panwrap_log_cont("%s", flag_info[i].name);
  48. flags &= ~flag_info[i].flag;
  49. }
  50. if (decodable_flags_found) {
  51. if (flags)
  52. panwrap_log_cont(" | 0x%llx", flags);
  53. panwrap_log_cont(")");
  54. }
  55. }
  56. void
  57. panwrap_log_hexdump(const void *data, size_t size, const char *indent)
  58. {
  59. unsigned char *buf = (void *) data;
  60. char alpha[HEXDUMP_ROW_LEN + 1];
  61. unsigned int i;
  62. if (!data) {
  63. panwrap_log("NULL pointer dereference(hexdump)\n");
  64. return;
  65. }
  66. for (i = 0; i < size; i++) {
  67. if (!(i % HEXDUMP_ROW_LEN))
  68. panwrap_log("%s%08X", indent, (unsigned int) i);
  69. if (!(i % HEXDUMP_COL_LEN))
  70. panwrap_log_cont(" ");
  71. if (((void *) (buf + i)) < ((void *) data)) {
  72. panwrap_log_cont(" ");
  73. alpha[i % HEXDUMP_ROW_LEN] = '.';
  74. } else {
  75. panwrap_log_cont(" %02x", buf[i]);
  76. if (isprint(buf[i]) && (buf[i] < 0xA0))
  77. alpha[i % HEXDUMP_ROW_LEN] = buf[i];
  78. else
  79. alpha[i % HEXDUMP_ROW_LEN] = '.';
  80. }
  81. if ((i % HEXDUMP_ROW_LEN) == HEXDUMP_ROW_LEN - 1) {
  82. alpha[HEXDUMP_ROW_LEN] = 0;
  83. panwrap_log_cont("\t|%s|\n", alpha);
  84. }
  85. }
  86. if (i % HEXDUMP_ROW_LEN) {
  87. for (i %= HEXDUMP_ROW_LEN; i < HEXDUMP_ROW_LEN; i++) {
  88. panwrap_log_cont(" ");
  89. alpha[i] = '.';
  90. if (i == HEXDUMP_ROW_LEN - 1) {
  91. alpha[HEXDUMP_ROW_LEN] = 0;
  92. panwrap_log_cont("\t|%s|\n", alpha);
  93. }
  94. }
  95. }
  96. }
  97. /**
  98. * Same as panwrap_log_hexdump, but trims off sections of the memory that look
  99. * empty
  100. */
  101. void
  102. panwrap_log_hexdump_trimmed(const void *data, size_t size, const char *indent)
  103. {
  104. const char *d = data;
  105. off_t trim_offset;
  106. size_t trim_size = size;
  107. bool trimming = false;
  108. if (!enable_hexdump_trimming)
  109. goto out;
  110. if (!data) {
  111. panwrap_log("NULL pointer dereference(hexdump)\n");
  112. return;
  113. }
  114. /*
  115. * Find the last byte of the memory region that looks initialized,
  116. * starting from the end
  117. */
  118. for (trim_offset = size - 1; trim_offset != -1; trim_offset--) {
  119. if (d[trim_offset] != 0)
  120. break;
  121. }
  122. if (trim_offset < 0)
  123. goto out;
  124. trimming = true;
  125. trim_size = trim_offset + 1;
  126. out:
  127. panwrap_log_hexdump(data, trim_size, indent);
  128. if (trimming)
  129. panwrap_log("%s<0 repeating %zu times>\n",
  130. indent, size - trim_size);
  131. }
  132. /* glibc libraries are versioned. bionic libraries are not. If you use
  133. * something else, define it here.
  134. */
  135. #ifdef __GLIBC__
  136. #define LIBC_NAME "libc.so.6"
  137. #else
  138. #define LIBC_NAME "libc.so"
  139. #endif
  140. /**
  141. * Grab the location of a symbol from the system's libc instead of our
  142. * preloaded one
  143. */
  144. void *
  145. __rd_dlsym_helper(const char *name)
  146. {
  147. static void *libc_dl;
  148. void *func;
  149. if (!libc_dl)
  150. libc_dl = dlopen(LIBC_NAME, RTLD_LAZY);
  151. if (!libc_dl) {
  152. fprintf(stderr, "Failed to dlopen libc: %s\n", dlerror());
  153. exit(-1);
  154. }
  155. func = dlsym(libc_dl, name);
  156. if (!func) {
  157. fprintf(stderr, "Failed to find %s: %s\n", name, dlerror());
  158. exit(-1);
  159. }
  160. return func;
  161. }
  162. static void
  163. timespec_add(struct timespec *tp, const struct timespec *value)
  164. {
  165. tp->tv_sec += value->tv_sec;
  166. tp->tv_nsec += value->tv_nsec;
  167. if (tp->tv_nsec >= 1e+9) {
  168. tp->tv_sec++;
  169. tp->tv_nsec -= 1e+9;
  170. }
  171. }
  172. static void
  173. timespec_subtract(struct timespec *tp, const struct timespec *value)
  174. {
  175. tp->tv_sec -= value->tv_sec;
  176. tp->tv_nsec -= value->tv_nsec;
  177. if (tp->tv_nsec < 0) {
  178. tp->tv_sec--;
  179. tp->tv_nsec = 1e+9 + tp->tv_nsec;
  180. }
  181. }
  182. static inline void
  183. __get_monotonic_time(const char *file, int line, struct timespec *tp)
  184. {
  185. if (clock_gettime(CLOCK_MONOTONIC, tp)) {
  186. fprintf(stderr, "%s:%d:Failed to call clock_gettime: %s\n",
  187. file, line, strerror(errno));
  188. exit(1);
  189. }
  190. }
  191. #define get_monotonic_time(tp) __get_monotonic_time(__FILE__, __LINE__, tp);
  192. /*
  193. * When logging information to the console (or whatever our output is), we
  194. * obviously spend a good bit of time just outputting logs. The offsets in
  195. * timestamps that can be caused by this can cause the time difference between
  196. * one operation the driver performed and another to be rather misleading.
  197. *
  198. * So, in order to avoid this we "freeze time" whenever we have panwrap code
  199. * executing with a overhead that's noticeable between logging lines, so that
  200. * our timestamps never reflect the amount of time an application spent in
  201. * panwrap's code.
  202. *
  203. * tl;dr: any time that passes while frozen is removed from timestamps
  204. */
  205. void
  206. panwrap_freeze_time()
  207. {
  208. if (!enable_timestamps)
  209. return;
  210. get_monotonic_time(&start_freeze_time);
  211. time_is_frozen = true;
  212. /*
  213. * Calculate the actual timestamp using the time where we first froze,
  214. * since we know it won't change until we unfreeze time
  215. */
  216. frozen_timestamp = start_freeze_time;
  217. timespec_subtract(&frozen_timestamp, &start_time);
  218. timespec_subtract(&frozen_timestamp, &total_time_frozen);
  219. }
  220. void
  221. panwrap_unfreeze_time()
  222. {
  223. struct timespec time_spent_frozen;
  224. if (!enable_timestamps || !time_is_frozen)
  225. return;
  226. time_is_frozen = false;
  227. get_monotonic_time(&time_spent_frozen);
  228. timespec_subtract(&time_spent_frozen, &start_freeze_time);
  229. timespec_add(&total_time_frozen, &time_spent_frozen);
  230. }
  231. static inline void
  232. timestamp_get(struct timespec *tp)
  233. {
  234. if (time_is_frozen) {
  235. *tp = frozen_timestamp;
  236. return;
  237. }
  238. get_monotonic_time(tp);
  239. timespec_subtract(tp, &start_time);
  240. timespec_subtract(tp, &total_time_frozen);
  241. }
  242. void
  243. panwrap_log(const char *format, ...)
  244. {
  245. struct timespec tp;
  246. va_list ap;
  247. if (enable_timestamps) {
  248. timestamp_get(&tp);
  249. fprintf(log_output,
  250. "panwrap [%.8lf]: ", tp.tv_sec + tp.tv_nsec / 1e+9F);
  251. } else {
  252. fprintf(log_output, "panwrap: ");
  253. }
  254. va_start(ap, format);
  255. vfprintf(log_output, format, ap);
  256. va_end(ap);
  257. }
  258. /* Eventually this function might do more */
  259. void
  260. panwrap_log_cont(const char *format, ...)
  261. {
  262. va_list ap;
  263. va_start(ap, format);
  264. vfprintf(log_output, format, ap);
  265. va_end(ap);
  266. }
  267. static bool
  268. parse_env_bool(const char *env, bool def)
  269. {
  270. const char *val = getenv(env);
  271. if (!val)
  272. return def;
  273. if (strcmp(val, "1") == 0)
  274. return true;
  275. else if (strcmp(val, "0") == 0)
  276. return false;
  277. fprintf(stderr,
  278. "Invalid value for %s: %s\n"
  279. "Valid values are 0 or 1\n",
  280. env, val);
  281. exit(1);
  282. }
  283. static void __attribute__((constructor))
  284. panwrap_util_init()
  285. {
  286. const char *env;
  287. if (parse_env_bool("PANWRAP_ENABLE_TIMESTAMPS", false)) {
  288. enable_timestamps = true;
  289. if (clock_gettime(CLOCK_MONOTONIC, &start_time)) {
  290. fprintf(stderr,
  291. "Failed to call clock_gettime: %s\n",
  292. strerror(errno));
  293. exit(1);
  294. }
  295. }
  296. enable_hexdump_trimming = parse_env_bool("PANWRAP_ENABLE_HEXDUMP_TRIM",
  297. true);
  298. env = getenv("PANWRAP_OUTPUT");
  299. if (env) {
  300. /* Don't try to reopen stderr or stdout, that won't work */
  301. if (strcmp(env, "/dev/stderr") == 0) {
  302. log_output = stderr;
  303. } else if (strcmp(env, "/dev/stdout") == 0) {
  304. log_output = stdout;
  305. } else {
  306. log_output = fopen(env, "w+");
  307. if (!log_output) {
  308. fprintf(stderr, "Failed to open %s: %s\n",
  309. env, strerror(errno));
  310. exit(1);
  311. }
  312. }
  313. } else {
  314. log_output = stdout;
  315. }
  316. srand(time(NULL));
  317. ioctl_fp = fopen("ioctls.bin", "wb");
  318. }