Skip to content

Instantly share code, notes, and snippets.

@iii-i
Created August 4, 2023 22:52
Show Gist options
  • Save iii-i/5adad06d911c46079d4388001b22ab61 to your computer and use it in GitHub Desktop.
Save iii-i/5adad06d911c46079d4388001b22ab61 to your computer and use it in GitHub Desktop.
vstrs_fuzz.c
#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