bool strlist_cmp(strlist *a, strlist *b) { if (a->count != b->count) return false; for (unsigned i = 0; i < a->count; ++i) if (0 != strcmp(strlist_get(a, i), strlist_get(b, i))) return false; return true; }
char *strlist2char(strlist *list) { char *data = strlist_get(list, 0); data = strcat_static(encodeStr(data), ""); for (unsigned i = 1; i < list->count; ++i) { data = strcat_static(data, " "); data = strcat_static(data, encodeStr(strlist_get(list, i))); } return data; }
static void execCmdline(strlist_t *cmdline, strlist_t *env, const char *workdir) { custr_t *execname; execname = execName(strlist_get(cmdline, 0), env, workdir); dlog("EXECNAME \"%s\"\n", custr_cstr(execname)); /* * We need to drop privs *after* we've setup /dev/zfd/[0-2] since that * requires being root. */ dlog("DROP PRIVS\n"); if (grp != NULL) { if (setgid(grp->gr_gid) != 0) { fatal(ERR_SETGID, "setgid(%d): %s\n", grp->gr_gid, strerror(errno)); } } if (pwd != NULL) { if (initgroups(pwd->pw_name, grp->gr_gid) != 0) { fatal(ERR_INITGROUPS, "initgroups(%s,%d): %s\n", pwd->pw_name, grp->gr_gid, strerror(errno)); } if (setuid(pwd->pw_uid) != 0) { fatal(ERR_SETUID, "setuid(%d): %s\n", pwd->pw_uid, strerror(errno)); } } execve(custr_cstr(execname), strlist_array(cmdline), strlist_array(env)); fatal(ERR_EXEC_FAILED, "execve(%s) failed: %s\n", execname, strerror(errno)); }
bool record_create(record_t *record, const char *prog, int argc, char **argv) { char hash_buf[SHA1_STRING_LEN]; const char *prog_bin = prog; unsigned i; record_clear(record); if (strrchr(prog, '/')) prog_bin = strrchr(prog, '/') + 1; if (!sha1_file(prog, hash_buf)) return false; strlist_push_back(&record->prog_line, prog_bin); strlist_push_back(&record->prog_line, sha1_file(prog, hash_buf)); for (i = 0; i < (unsigned)argc; ++i) strlist_push_back(&record->prog_line, argv[i]); strlist lib_list = STRLIST_INITIALIZER; get_libs(&lib_list, prog); for (i = 0; i < lib_list.count; ++i) { const char *lib_path = strlist_get(&lib_list, i); if (!sha1_file(lib_path, hash_buf)) continue; strlist_push_back(&record->lib_line, lib_path); strlist_push_back(&record->lib_line, sha1_file(lib_path, hash_buf)); } record->enabled = true; return true; }
strlist libs_diff(strlist *prev_run, strlist *curr_run) { strlist result = STRLIST_INITIALIZER; char buf[STRING_MAX]; unsigned prev_cnt = 0, curr_cnt = 0; char *prev_ptr = strlist_get(prev_run, prev_cnt); char *curr_ptr = strlist_get(curr_run, curr_cnt); int retval = 0; while (prev_ptr || curr_ptr) { if (prev_ptr && curr_ptr) { retval = strcmp(prev_ptr, curr_ptr); if (retval == 0) { // Libraries match. Compare file contents. char *prev_hash = strlist_get(prev_run, ++prev_cnt); char *curr_hash = strlist_get(curr_run, ++curr_cnt); if (strcmp(prev_hash, curr_hash) != 0) { snprintf(buf, sizeof(buf), "* %s has changed since last run.", prev_ptr); strlist_push_back(&result, buf); } prev_ptr = strlist_get(prev_run, ++prev_cnt); curr_ptr = strlist_get(curr_run, ++curr_cnt); continue; } } if (!curr_ptr || retval < 0) { // If (there are no more libraries from `ldd`) OR // (library from history record not found in `ldd` list) snprintf(buf, sizeof(buf), "* Mutatee is no longer dependent on %s.", prev_ptr); strlist_push_back(&result, buf); ++prev_cnt; // Skip digest string. prev_ptr = strlist_get(prev_run, ++prev_cnt); } else if (!prev_ptr || retval > 0) { // If (there are no more libraries from the history record) OR // (library from `ldd` not found in history record list) snprintf(buf, sizeof(buf), "* Mutatee is now dependent on %s.", curr_ptr); strlist_push_back(&result, buf); ++curr_cnt; // Skip digest string. curr_ptr = strlist_get(curr_run, ++curr_cnt); } } return result; }
void record_update(record_t *newRecord) { FILE *index_fd; FILE *new_fd; char index_filename[PATH_MAX]; char new_index_filename[PATH_MAX]; strncpy(index_filename, config.record_dir, sizeof(index_filename)); strncat(index_filename, "/", sizeof(index_filename) - strlen(index_filename)); strncat(index_filename, HISTORY_RECORD_INDEX_FILE, sizeof(index_filename) - strlen(index_filename)); errno = 0; index_fd = fopen(index_filename, "r"); if (!index_fd) { fprintf(stderr, "Could not open %s\n", index_filename); return; } strncpy(new_index_filename, index_filename, sizeof(new_index_filename)); strncat(new_index_filename, ".update", sizeof(new_index_filename) - strlen(new_index_filename)); new_fd = fopen(new_index_filename, "w"); if (!new_fd) { fprintf(stderr, "Could not open %s\n", new_index_filename); return; } char *buf = NULL; bool found = false; strlist prog_line = STRLIST_INITIALIZER; while ( (buf = fgets_static(index_fd))) { chomp(buf); if (buf[0] == '\t' || buf[0] == '\0') { fprintf(new_fd, "%s\n", buf); buf[0] = '\0'; continue; } prog_line = char2strlist(buf); if (strlist_cmp(&prog_line, &newRecord->prog_line)) { fprintf(new_fd, "%s\n", buf); strlist_push_front(&newRecord->lib_line, newRecord->filename); buf = strlist2char(&newRecord->lib_line); fprintf(new_fd, "\t%s\n", buf); strlist_pop_front(&newRecord->lib_line); while ( (buf = fgets_static(index_fd)) && buf[0] == '\t') { chomp(buf); strlist lib_line = char2strlist(buf); strlist_pop_front(&lib_line); if (!strlist_cmp(&lib_line, &newRecord->lib_line)) fprintf(new_fd, "%s\n", buf); strlist_clear(&lib_line); } fprintf(new_fd, "%s", buf); // NOTE: Do not print "%s\n" here. found = true; break; } if (strcmp(strlist_get(&newRecord->prog_line, 0), strlist_get(&prog_line, 0)) < 0) break; strlist_clear(&prog_line); fprintf(new_fd, "%s\n", buf); buf[0] = '\0'; } // New binary signature entry. if (!found) { char *buf2; buf2 = strlist2char(&newRecord->prog_line); fprintf(new_fd, "%s\n", buf2); strlist_push_front(&newRecord->lib_line, newRecord->filename); buf2 = strlist2char(&newRecord->lib_line); fprintf(new_fd, "\t%s\n\n", buf2); strlist_pop_front(&newRecord->lib_line); if (buf && buf[0] != '\0') fprintf(new_fd, "%s\n", buf); } while ( (buf = fgets_static(index_fd))) fprintf(new_fd, "%s", buf); // NOTE: Do not print "%s\n" here. fclose(index_fd); fclose(new_fd); unlink(index_filename); rename(new_index_filename, index_filename); }
bool record_search(record_t *newRecord) { FILE *index_fd; char *index_filename; bool found = false, latest = true; index_filename = sprintf_static("%s/%s", config.record_dir, HISTORY_RECORD_INDEX_FILE); errno = 0; index_fd = fopen(index_filename, "r"); if (errno && errno == ENOENT) { index_fd = fopen(index_filename, "w"); if (!index_fd) { fprintf(config.outfd, "*\n* Error opening history record index %s. Disabling history record.\n*\n", index_filename); newRecord->enabled = false; return false; } fclose(index_fd); } else if (!index_fd) { fprintf(config.outfd, "*\n* Error opening history record index %s. Disabling history record.\n*\n", index_filename); newRecord->enabled = false; return false; } else { // We should use C++ string instead to avoid buffer overflows. char *buf; while ( (buf = fgets_static(index_fd))) { if (buf[0] == '\t' || buf[0] == '\n') continue; chomp(buf); strlist prog_line = char2strlist(buf); if (strlist_cmp(&prog_line, &newRecord->prog_line)) { strlist diff_list = STRLIST_INITIALIZER; while (!found && (buf = fgets_static(index_fd)) && buf[0] == '\t') { chomp(buf); strlist lib_line = char2strlist(buf + 1); strncpy(newRecord->filename, strlist_get(&lib_line, 0), sizeof(newRecord->filename)); strlist_pop_front(&lib_line); if (strlist_cmp(&lib_line, &newRecord->lib_line)) { found = true; } else { if (latest) diff_list = libs_diff(&lib_line, &newRecord->lib_line); latest = false; } strlist_clear(&lib_line); } if (!found) { fprintf(config.outfd, "* Warning: Current library set unknown. Differences from latest run include:\n"); fprintf(config.outfd, "*\n"); for (unsigned i = 0; i < diff_list.count; ++i) fprintf(config.outfd, "%s\n", strlist_get(&diff_list, i)); } else if (!latest) fprintf(config.outfd, "* Warning: Current library signature does not match latest run.\n"); strlist_clear(&diff_list); } strlist_clear(&prog_line); } fclose(index_fd); } if (!found) { // Fill storage file information const char *prog_file = strlist_get(&newRecord->prog_line, 0); if (strrchr(prog_file, '/')) prog_file = strrchr(prog_file, '/') + 1; snprintf(newRecord->filename, sizeof(newRecord->filename), "%s/%s-XXXXXX", config.record_dir, prog_file); int file_desc = mkstemp(newRecord->filename); newRecord->fd = fdopen(file_desc, "a"); } else { newRecord->fd = fopen(newRecord->filename, "a"); } char timestr[STRING_MAX]; time_t timestamp = time(NULL); strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %Z", localtime(×tamp)); fprintf(newRecord->fd, "Log start: %s\n", timestr); fprintf(newRecord->fd, "--------------------------------------------------------------------------------\n"); char raw_filename[ PATH_MAX ]; strncpy(raw_filename, newRecord->filename, sizeof(raw_filename)); strncat(raw_filename, ".raw", sizeof(raw_filename) - strlen(raw_filename)); newRecord->raw_fd = fopen(raw_filename, "a"); fprintf(newRecord->raw_fd, "Raw transcript log start: %s\n", timestr); fprintf(newRecord->raw_fd, "--------------------------------------------------------------------------------\n"); return (found && latest); }