Skip to content

Commit

Permalink
Add string hooks for strcmp/strncmp/getenv/strstr and trigger hyperca…
Browse files Browse the repository at this point in the history
…lls when they happen
  • Loading branch information
Andrew Fasano committed Feb 5, 2024
1 parent c2fd117 commit 4c8e669
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 0 deletions.
62 changes: 62 additions & 0 deletions hypercall.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
static inline void igloo_hypercall(unsigned long num, unsigned long arg1) {
#if defined(CONFIG_MIPS)
register unsigned long a0 asm("a0") = num;
register unsigned long a1 asm("a1") = arg1;

asm volatile(
"movz $0, $0, $0"
: "+r"(a0) // Input and output in R0
: "r"(a1) // arg1 in register A1
: // No clobber
);


#elif defined(CONFIG_ARM)
register uint32_t r0 asm("r0") = num;
register uint32_t r1 asm("r1") = arg1;
asm volatile(
"mov r0, %0 \t\n\
mov r1, %1 \t\n\
mcr p7, 0, r0, c0, c0, 0"
:
: "r"(r0), "r"(r1)
:
);
#else
#error "No igloo_hypercall support for architecture"
#endif
}

static inline unsigned long igloo_hypercall2(unsigned long num, unsigned long arg1, unsigned long arg2) {
#if defined(CONFIG_ARM)
register unsigned long r0 asm("r0") = num;
register unsigned long r1 asm("r1") = arg1;
register unsigned long r2 asm("r2") = arg2;

asm volatile(
"mcr p7, 0, r0, c0, c0, 0"
: "+r"(r0) // Input and output
: "r"(r1), "r"(r2)
: // No clobber
);

return r0;

#elif defined(CONFIG_MIPS)
register unsigned long a0 asm("a0") = num;
register unsigned long a1 asm("a1") = arg1;
register unsigned long a2 asm("a2") = arg2;

asm volatile(
"movz $0, $0, $0"
: "+r"(a0) // Input and output in R0
: "r"(a1) , "r" (a2)// arg1 in register A1
: // No clobber
);
return a0;

#else
#error "No igloo_hypercall2 support for architecture"
return 0;
#endif
}
2 changes: 2 additions & 0 deletions nvram.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "alias.h"
#include "nvram.h"
#include "config.h"
#include "strings.h"

/* Generate variable declarations for external NVRAM data. */
#define NATIVE(a, b)
Expand Down Expand Up @@ -915,3 +916,4 @@ int agApi_fwGetNextTriggerConf(char *a1)

// Hack to use static variables in shared library
#include "alias.c"
#include "strings.c"
137 changes: 137 additions & 0 deletions strings.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#ifndef INCLUDE_STRINGS_C
#define INCLUDE_STRINGS_C

#include "strings.h"

// ENUM for sources: strcmp, strncmp, getenv
enum source {
STRCMP,
STRNCMP,
GETENV
};
typedef struct {
enum source source;
const char* value;
} match;

void log_match(match m) {
int cmd = -1;
switch (m.source) {
case STRCMP:
cmd = 101;
break;
case STRNCMP:
cmd = 102;
break;
case GETENV:
cmd = 103;
break;
}

// TODO: we could support retries
igloo_hypercall2(cmd, (unsigned long)m.value, strlen(m.value));
}



// Simple string length calculation
size_t minimal_strlen(const char *s) {
size_t len = 0;
while (s[len]) ++len;
return len;
}

int minimal_strcmp(const char *s1, const char *s2, short do_log) {
size_t i = 0;
while (s1[i] && s2[i]) {
if (s1[i] != s2[i]) {
break;
}
i++;
}
if (do_log) {
// Additional logic to log if TARGET_VALUE is present
if (minimal_strncmp(s1, TARGET_VALUE, sizeof(TARGET_VALUE), 0) == 0) {
log_match((match) {STRCMP, s2});
} else if (minimal_strncmp(s2, TARGET_VALUE, sizeof(TARGET_VALUE), 0) == 0) {
log_match((match) {STRCMP, s1});
}
}
return s1[i] - s2[i];
}

int minimal_strncmp(const char *s1, const char *s2, size_t n, short do_log) {
for (size_t i = 0; i < n; ++i) {
if (s1[i] != s2[i] || !s1[i]) {
// Additional logic to log if TARGET_VALUE is present
if (do_log) {
if (minimal_strncmp(s1, TARGET_VALUE, sizeof(TARGET_VALUE), 0) == 0) {
log_match((match) {STRNCMP, s2});
} else if (minimal_strncmp(s2, TARGET_VALUE, sizeof(TARGET_VALUE), 0) == 0) {
log_match((match) {STRNCMP, s1});
}
}
return s1[i] - s2[i];
}
}
return 0;
}

int strcmp(const char *s1, const char *s2) {
return minimal_strcmp(s1, s2, 1);
}

int strncmp(const char *s1, const char *s2, size_t n) {
return minimal_strncmp(s1, s2, n, 1);
}

char *minimal_getenv(const char *name) {
size_t len = minimal_strlen(name);
for (char **env = environ; *env; ++env) {
if (minimal_strncmp(*env, name, len, 0) == 0 && (*env)[len] == '=') {
return *env + len + 1; // Return the value part of the KEY=value pair
}
}
return NULL; // Not found
}

char *getenv(const char *name) {
// Call the original getenv
char *result = minimal_getenv(name);

// if the first len(TARGET_VALUE) characters of result match our target, log it
if (result && minimal_strncmp(result, TARGET_VALUE, minimal_strlen(result), 0) == 0) {
log_match((match) {GETENV, name});
}

// Return the original result
return result;
}

char *strstr(const char *haystack, const char *needle) {
if (!haystack || !needle) return NULL;

// It's not actually a match - strstr is a bit more
// involved so we just pass the args out every time
igloo_hypercall2(104, (unsigned long)haystack, (unsigned long)needle);

for (; *haystack; ++haystack) {
const char *h = haystack;
const char *n = needle;

while (*n && *h && *h == *n) {
++h;
++n;
}

if (!*n) {
// Found needle in haystack
return (char *)haystack;
}
}

return NULL;
}


#endif
16 changes: 16 additions & 0 deletions strings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef INCLUDE_STRINGS_H
#define INCLUDE_STRINGS_H

#include "hypercall.h"
#include <stddef.h>

#define TARGET_VALUE "DYNVALDYNVALDYNVAL"
extern char **environ;

size_t minimal_strlen(const char *s);
int minimal_strncmp(const char *s1, const char *s2, size_t n, short do_log);
int minimal_strcmp(const char *s1, const char *s2, short do_log);
char *minimal_getenv(const char *name);
char *getenv(const char *name);

#endif

0 comments on commit 4c8e669

Please sign in to comment.