forked from firmadyne/libnvram
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add string hooks for strcmp/strncmp/getenv/strstr and trigger hyperca…
…lls when they happen
- Loading branch information
Andrew Fasano
committed
Feb 5, 2024
1 parent
c2fd117
commit 4c8e669
Showing
4 changed files
with
217 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |