Skip to content

Commit

Permalink
Unit test for path sanitation porting
Browse files Browse the repository at this point in the history
  • Loading branch information
henrybear327 committed Nov 23, 2023
1 parent 47bab96 commit dbd1d4a
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ build/mini-gdbstub
build/softfloat
build/cache/
build/map/
build/path/
*.o
*.o.d
tests/**/*.elf
Expand Down
36 changes: 35 additions & 1 deletion mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ MAP_TEST_SRCDIR := tests/map
MAP_TEST_OUTDIR:= build/map
MAP_TEST_TARGET := $(MAP_TEST_OUTDIR)/test-map

PATH_TEST_SRCDIR := tests/path
PATH_TEST_OUTDIR := build/path
PATH_TEST_TARGET := $(PATH_TEST_OUTDIR)/test-path

CACHE_TEST_OBJS := \
test-cache.o

MAP_TEST_OBJS := \
test-map.o \
mt19937.o

PATH_TEST_OBJS := \
test-path.o

CACHE_TEST_OBJS := $(addprefix $(CACHE_TEST_OUTDIR)/, $(CACHE_TEST_OBJS)) \
$(OUT)/cache.o $(OUT)/mpool.o
OBJS += $(CACHE_TEST_OBJS)
Expand All @@ -23,6 +30,11 @@ MAP_TEST_OBJS := $(addprefix $(MAP_TEST_OUTDIR)/, $(MAP_TEST_OBJS)) \
OBJS += $(MAP_TEST_OBJS)
deps += $(MAP_TEST_OBJS:%.o=%.o.d)

PATH_TEST_OBJS := $(addprefix $(PATH_TEST_OUTDIR)/, $(PATH_TEST_OBJS)) \
$(OUT)/utils.o
OBJS += $(PATH_TEST_OBJS)
deps += $(PATH_TEST_OBJS:%.o=%.o.d)

# Check adaptive replacement cache policy is enabled or not, default is LFU
ifeq ($(ENABLE_ARC), 1)
CACHE_TEST_ACTIONS := \
Expand All @@ -43,8 +55,9 @@ endif

CACHE_TEST_OUT = $(addprefix $(CACHE_TEST_OUTDIR)/, $(CACHE_TEST_ACTIONS:%=%.out))
MAP_TEST_OUT = $(MAP_TEST_TARGET).out
PATH_TEST_OUT = $(PATH_TEST_TARGET).out

tests : run-test-cache run-test-map
tests : run-test-cache run-test-map run-test-path

run-test-cache: $(CACHE_TEST_OUT)
$(Q)$(foreach e,$(CACHE_TEST_ACTIONS),\
Expand All @@ -66,6 +79,15 @@ run-test-map: $(MAP_TEST_OUT)
$(PRINTF) "Failed.\n"; \
fi;

run-test-path: $(PATH_TEST_OUT)
$(Q)$(PATH_TEST_TARGET)
$(VECHO) "Running test-path ... "; \
if [ $$? -eq 0 ]; then \
$(call notice, [OK]); \
else \
$(PRINTF) "Failed.\n"; \
fi;

$(CACHE_TEST_OUT): $(CACHE_TEST_TARGET)
$(Q)$(foreach e,$(CACHE_TEST_ACTIONS),\
$(CACHE_TEST_TARGET) $(CACHE_TEST_SRCDIR)/$(e).in > $(CACHE_TEST_OUTDIR)/$(e).out; \
Expand All @@ -91,3 +113,15 @@ $(MAP_TEST_OUTDIR)/%.o: $(MAP_TEST_SRCDIR)/%.c
$(VECHO) " CC\t$@\n"
$(Q)mkdir -p $(dir $@)
$(Q)$(CC) -o $@ $(CFLAGS) -I./src -c -MMD -MF $@.d $<

$(PATH_TEST_OUT): $(PATH_TEST_TARGET)
$(Q)touch $@

$(PATH_TEST_TARGET): $(PATH_TEST_OBJS)
$(VECHO) " CC\t$@\n"
$(Q)$(CC) $^ -o $@

$(PATH_TEST_OUTDIR)/%.o: $(PATH_TEST_SRCDIR)/%.c
$(VECHO) " CC\t$@\n"
$(Q)mkdir -p $(dir $@)
$(Q)$(CC) -o $@ $(CFLAGS) -I./src -c -MMD -MF $@.d $<
4 changes: 2 additions & 2 deletions src/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,13 @@ bool elf_load(elf_t *e, riscv_t *rv, memory_t *mem)
return true;
}

bool elf_open(elf_t *e, const char *orig_path)
bool elf_open(elf_t *e, const char *input)
{
/* free previous memory */
if (e->raw_data)
release(e);

char *path = sanitize_path(orig_path);
char *path = sanitize_path(input);

#if defined(USE_MMAP)
int fd = open(path, O_RDONLY);
Expand Down
1 change: 1 addition & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "elf.h"
#include "state.h"
#include "utils.h"

/* enable program trace mode */
static bool opt_trace = false;
Expand Down
40 changes: 19 additions & 21 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#endif
#endif

const int MAX_PATH_LEN = 1024;
#define MAX_PATH_LEN 1024

static void get_time_info(int32_t *tv_sec, int32_t *tv_usec)
{
Expand Down Expand Up @@ -72,9 +72,9 @@ void rv_clock_gettime(struct timespec *tp)
tp->tv_nsec = tv_usec / 1000; /* Transfer to microseconds */
}

char *sanitize_path(const char *orig_path)
char *sanitize_path(const char *input)
{
size_t n = strnlen(orig_path, MAX_PATH_LEN);
size_t n = strnlen(input, MAX_PATH_LEN);

char *ret = malloc(MAX_PATH_LEN + 1);
memset(ret, '\0', MAX_PATH_LEN + 1);
Expand All @@ -86,15 +86,15 @@ char *sanitize_path(const char *orig_path)
return ret;
}

int rooted = (orig_path[0] == '/');
int rooted = (input[0] == '/');

/*
* Invariants:
* reading from path; r is index of next byte to process -> path[r]
* writing to buf; w is index of next byte to write -> ret[strlen(ret)]
* dotdot is index in buf where .. must stop, either because
* a) it is the leading slash
* b) it is a leading ../../.. prefix.
* reading from path; r is index of next byte to process -> path[r]
* writing to buf; w is index of next byte to write -> ret[strlen(ret)]
* dotdot is index in buf where .. must stop, either because:
* a) it is the leading slash
* b) it is a leading ../../.. prefix.
*/
size_t w = 0;
size_t r = 0;
Expand All @@ -107,15 +107,15 @@ char *sanitize_path(const char *orig_path)
}

while (r < n) {
if (orig_path[r] == '/') {
if (input[r] == '/') {
/* empty path element */
r++;
} else if (orig_path[r] == '.' &&
(r + 1 == n || orig_path[r + 1] == '/')) {
} else if (input[r] == '.' &&
(r + 1 == n || input[r + 1] == '/')) {
/* . element */
r++;
} else if (orig_path[r] == '.' && orig_path[r + 1] == '.' &&
(r + 2 == n || orig_path[r + 2] == '/')) {
} else if (input[r] == '.' && input[r + 1] == '.' &&
(r + 2 == n || input[r + 2] == '/')) {
/* .. element: remove to last / */
r += 2;

Expand Down Expand Up @@ -146,13 +146,11 @@ char *sanitize_path(const char *orig_path)
}

/* copy element */
for (; r < n && orig_path[r] != '/'; r++) {
ret[w] = orig_path[r];
for (; r < n && input[r] != '/'; r++) {
ret[w] = input[r];
w++;
}
}
// printf("w = %ld, r = %ld, dotdot = %ld\nret = %s\n", w, r, dotdot,
// ret);
}

/* Turn empty string into "." */
Expand All @@ -161,8 +159,8 @@ char *sanitize_path(const char *orig_path)
w++;
}

for (size_t i = w; i < n; i++) {
ret[i] = '\0';
}
/* starting from w till the end, we should mark it as \0 since that part of the buffer is not used */
memset(ret + w, '\0', sizeof(MAX_PATH_LEN + 1 - w));

return ret;
}
4 changes: 3 additions & 1 deletion src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ void rv_clock_gettime(struct timespec *tp);
* Getting Dot-Dot Right,”
* https://9p.io/sys/doc/lexnames.html
*/
char *sanitize_path(const char *orig_path);
char *sanitize_path(const char *input);

void sanitize_path_test();
75 changes: 75 additions & 0 deletions tests/path/test-path.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utils.h"

void compare(char *input, char *expected_output)
{
char *input_sanitized = sanitize_path(input);
if (strcmp(input_sanitized, expected_output)) {
printf("\n\nInput =\t\t\t%s\nOutput =\t\t%s\nExpected output =\t%s\n",
input, input_sanitized, expected_output);

exit(1);
}

free(input_sanitized);
}

void sanitize_path_test()
{
/* Already clean */
compare("", ".");
compare("abc", "abc");
compare("abc/def", "abc/def");
compare(".", ".");
compare("..", "..");
compare("../..", "../..");
compare("../../abc", "../../abc");
compare("/abc", "/abc");
compare("/", "/");

/* Remove trailing slash */
compare("abc/", "abc");
compare("abc/def/", "abc/def");
compare("a/b/c/", "a/b/c");
compare("./", ".");
compare("../", "..");
compare("../../", "../..");
compare("/abc/", "/abc");

/* Remove doubled slash */
compare("abc//def//ghi", "abc/def/ghi");
compare("//abc", "/abc");
compare("///abc", "/abc");
compare("//abc//", "/abc");
compare("abc//", "abc");

/* Remove . elements */
compare("abc/./def", "abc/def");
compare("/./abc/def", "/abc/def");
compare("abc/.", "abc");

/* Remove .. elements */
compare("abc/def/ghi/../jkl", "abc/def/jkl");
compare("abc/def/../ghi/../jkl", "abc/jkl");
compare("abc/def/..", "abc");
compare("abc/def/../..", ".");
compare("/abc/def/../..", "/");
compare("abc/def/../../..", "..");
compare("/abc/def/../../..", "/");
compare("abc/def/../../../ghi/jkl/../../../mno", "../../mno");

/* Combinations */
compare("abc/./../def", "def");
compare("abc//./../def", "def");
compare("abc/../../././../def", "../../def");
}

int main()
{
sanitize_path_test();

return 0;
}

0 comments on commit dbd1d4a

Please sign in to comment.