Created
August 4, 2023 22:52
-
-
Save iii-i/5adad06d911c46079d4388001b22ab61 to your computer and use it in GitHub Desktop.
vstrs_fuzz.c
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
#include <assert.h> | |
#include <stdbool.h> | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
#define g_assert assert | |
#define g_assert_not_reached() assert(false) | |
#define HOST_BIG_ENDIAN 1 | |
/* begin copy-paste */ | |
#define MIN(x,y) ((x) < (y) ? (x) : (y)) | |
#if !HOST_BIG_ENDIAN | |
#define H1(x) ((x) ^ 7) | |
#define H2(x) ((x) ^ 3) | |
#define H4(x) ((x) ^ 1) | |
#else | |
#define H1(x) (x) | |
#define H2(x) (x) | |
#define H4(x) (x) | |
#endif | |
typedef enum MemOp { | |
MO_8 = 0, | |
MO_16 = 1, | |
MO_32 = 2, | |
MO_64 = 3, | |
} MemOp; | |
typedef union S390Vector { | |
uint64_t doubleword[2]; | |
uint32_t word[4]; | |
uint16_t halfword[8]; | |
uint8_t byte[16]; | |
__int128_t v; | |
} S390Vector; | |
static inline uint8_t s390_vec_read_element8(const S390Vector *v, uint8_t enr) | |
{ | |
g_assert(enr < 16); | |
return v->byte[H1(enr)]; | |
} | |
static inline uint16_t s390_vec_read_element16(const S390Vector *v, uint8_t enr) | |
{ | |
g_assert(enr < 8); | |
return v->halfword[H2(enr)]; | |
} | |
static inline uint32_t s390_vec_read_element32(const S390Vector *v, uint8_t enr) | |
{ | |
g_assert(enr < 4); | |
return v->word[H4(enr)]; | |
} | |
static inline uint64_t s390_vec_read_element64(const S390Vector *v, uint8_t enr) | |
{ | |
g_assert(enr < 2); | |
return v->doubleword[enr]; | |
} | |
static inline uint64_t s390_vec_read_element(const S390Vector *v, uint8_t enr, | |
uint8_t es) | |
{ | |
switch (es) { | |
case MO_8: | |
return s390_vec_read_element8(v, enr); | |
case MO_16: | |
return s390_vec_read_element16(v, enr); | |
case MO_32: | |
return s390_vec_read_element32(v, enr); | |
case MO_64: | |
return s390_vec_read_element64(v, enr); | |
default: | |
g_assert_not_reached(); | |
} | |
} | |
static inline void s390_vec_write_element8(S390Vector *v, uint8_t enr, | |
uint8_t data) | |
{ | |
g_assert(enr < 16); | |
v->byte[H1(enr)] = data; | |
} | |
static inline void s390_vec_write_element16(S390Vector *v, uint8_t enr, | |
uint16_t data) | |
{ | |
g_assert(enr < 8); | |
v->halfword[H2(enr)] = data; | |
} | |
static inline void s390_vec_write_element32(S390Vector *v, uint8_t enr, | |
uint32_t data) | |
{ | |
g_assert(enr < 4); | |
v->word[H4(enr)] = data; | |
} | |
static inline void s390_vec_write_element64(S390Vector *v, uint8_t enr, | |
uint64_t data) | |
{ | |
g_assert(enr < 2); | |
v->doubleword[enr] = data; | |
} | |
static inline void s390_vec_write_element(S390Vector *v, uint8_t enr, | |
uint8_t es, uint64_t data) | |
{ | |
switch (es) { | |
case MO_8: | |
s390_vec_write_element8(v, enr, data); | |
break; | |
case MO_16: | |
s390_vec_write_element16(v, enr, data); | |
break; | |
case MO_32: | |
s390_vec_write_element32(v, enr, data); | |
break; | |
case MO_64: | |
s390_vec_write_element64(v, enr, data); | |
break; | |
default: | |
g_assert_not_reached(); | |
} | |
} | |
static int vstrs(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, | |
const S390Vector *v4, uint8_t es, bool zs) | |
{ | |
int substr_elen, i, j, k, cc; | |
int nelem = 16 >> es; | |
int str_leftmost_0; | |
substr_elen = s390_vec_read_element8(v4, 7) >> es; | |
/* If ZS, bound substr length by min(nelem, strlen(v3)). */ | |
if (zs) { | |
substr_elen = MIN(substr_elen, nelem); | |
for (i = 0; i < substr_elen; i++) { | |
if (s390_vec_read_element(v3, i, es) == 0) { | |
substr_elen = i; | |
break; | |
} | |
} | |
} | |
if (substr_elen == 0) { | |
cc = 2; /* full match for degenerate case of empty substr */ | |
k = 0; | |
goto done; | |
} | |
/* If ZS, look for eos in the searched string. */ | |
str_leftmost_0 = nelem; | |
if (zs) { | |
for (k = 0; k < nelem; k++) { | |
if (s390_vec_read_element(v2, k, es) == 0) { | |
str_leftmost_0 = k; | |
break; | |
} | |
} | |
} | |
cc = str_leftmost_0 == nelem ? 0 : 1; /* No match. */ | |
for (k = 0; k < nelem; k++) { | |
i = MIN(nelem, k + substr_elen); | |
for (j = k; j < i; j++) { | |
uint32_t e2 = s390_vec_read_element(v2, j, es); | |
uint32_t e3 = s390_vec_read_element(v3, j - k, es); | |
if (e2 != e3) { | |
break; | |
} | |
} | |
if (j == i) { | |
/* All elements matched. */ | |
if (k > str_leftmost_0) { | |
cc = 1; /* Ignored match. */ | |
k = nelem; | |
} else if (i - k == substr_elen) { | |
cc = 2; /* Full match. */ | |
} else { | |
cc = 3; /* Partial match. */ | |
} | |
break; | |
} | |
} | |
done: | |
s390_vec_write_element64(v1, 0, k << es); | |
s390_vec_write_element64(v1, 1, 0); | |
return cc; | |
} | |
/* end copy-paste */ | |
extern char insn[]; | |
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { | |
char *insn_page = (char *)((uintptr_t)&insn & ~0xFFFULL); | |
char *insn_end = (char *)&insn + 6; | |
S390Vector v1, v1_exp, v2, v3, v4; | |
int cc, cc_exp, err; | |
if (len < 50) { | |
return 0; | |
} | |
memcpy(&v2, &buf[0], 16); | |
memcpy(&v3, &buf[16], 16); | |
memcpy(&v4, &buf[32], 16); | |
v4.byte[7] %= 17; | |
cc = vstrs(&v1, &v2, &v3, &v4, buf[48] % 3, buf[49] & 2); | |
err = mprotect(insn_page, insn_end - insn_page, | |
PROT_READ | PROT_WRITE | PROT_EXEC); | |
assert(err == 0); | |
insn[2] = (insn[2] & 0xf0) | (buf[48] % 3); | |
insn[3] = (insn[3] & 0x0f) | ((buf[49] & 2) << 4); | |
asm("insn: vstrs %[v1],%[v2],%[v3],%[v4],%[m5],%[m6]\n" | |
"ipm %[cc]" | |
: [v1] "=v" (v1_exp.v) | |
, [cc] "=r" (cc_exp) | |
: [v2] "v" (v2.v) | |
, [v3] "v" (v3.v) | |
, [v4] "v" (v4.v) | |
, [m5] "i" (0) | |
, [m6] "i" (0) | |
: "cc"); | |
cc_exp = (cc_exp >> 28) & 3; | |
assert(cc == cc_exp); | |
assert(memcmp(&v1, &v1_exp, sizeof(v1)) == 0); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment