map[SimplifiedCRepro:// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/loop.h>
#ifndef __NR_memfd_create
#define __NR_memfd_create 319
#endif
static unsigned long long procid;
//% This code is derived from puff.{c,h}, found in the zlib development. The
//% original files come with the following copyright notice:
//% Copyright (C) 2002-2013 Mark Adler, all rights reserved
//% version 2.3, 21 Jan 2013
//% This software is provided 'as-is', without any express or implied
//% warranty. In no event will the author be held liable for any damages
//% arising from the use of this software.
//% Permission is granted to anyone to use this software for any purpose,
//% including commercial applications, and to alter it and redistribute it
//% freely, subject to the following restrictions:
//% 1. The origin of this software must not be misrepresented; you must not
//% claim that you wrote the original software. If you use this software
//% in a product, an acknowledgment in the product documentation would be
//% appreciated but is not required.
//% 2. Altered source versions must be plainly marked as such, and must not be
//% misrepresented as being the original software.
//% 3. This notice may not be removed or altered from any source distribution.
//% Mark Adler madler@alumni.caltech.edu
//% BEGIN CODE DERIVED FROM puff.{c,h}
#define MAXBITS 15
#define MAXLCODES 286
#define MAXDCODES 30
#define MAXCODES (MAXLCODES + MAXDCODES)
#define FIXLCODES 288
struct puff_state {
unsigned char* out;
unsigned long outlen;
unsigned long outcnt;
const unsigned char* in;
unsigned long inlen;
unsigned long incnt;
int bitbuf;
int bitcnt;
jmp_buf env;
};
static int puff_bits(struct puff_state* s, int need)
{
long val = s->bitbuf;
while (s->bitcnt < need) {
if (s->incnt == s->inlen)
longjmp(s->env, 1);
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
s->bitcnt += 8;
}
s->bitbuf = (int)(val >> need);
s->bitcnt -= need;
return (int)(val & ((1L << need) - 1));
}
static int puff_stored(struct puff_state* s)
{
s->bitbuf = 0;
s->bitcnt = 0;
if (s->incnt + 4 > s->inlen)
return 2;
unsigned len = s->in[s->incnt++];
len |= s->in[s->incnt++] << 8;
if (s->in[s->incnt++] != (~len & 0xff) ||
s->in[s->incnt++] != ((~len >> 8) & 0xff))
return -2;
if (s->incnt + len > s->inlen)
return 2;
if (s->outcnt + len > s->outlen)
return 1;
for (; len--; s->outcnt++, s->incnt++) {
if (s->in[s->incnt])
s->out[s->outcnt] = s->in[s->incnt];
}
return 0;
}
struct puff_huffman {
short* count;
short* symbol;
};
static int puff_decode(struct puff_state* s, const struct puff_huffman* h)
{
int first = 0;
int index = 0;
int bitbuf = s->bitbuf;
int left = s->bitcnt;
int code = first = index = 0;
int len = 1;
short* next = h->count + 1;
while (1) {
while (left--) {
code |= bitbuf & 1;
bitbuf >>= 1;
int count = *next++;
if (code - count < first) {
s->bitbuf = bitbuf;
s->bitcnt = (s->bitcnt - len) & 7;
return h->symbol[index + (code - first)];
}
index += count;
first += count;
first <<= 1;
code <<= 1;
len++;
}
left = (MAXBITS + 1) - len;
if (left == 0)
break;
if (s->incnt == s->inlen)
longjmp(s->env, 1);
bitbuf = s->in[s->incnt++];
if (left > 8)
left = 8;
}
return -10;
}
static int puff_construct(struct puff_huffman* h, const short* length, int n)
{
int len;
for (len = 0; len <= MAXBITS; len++)
h->count[len] = 0;
int symbol;
for (symbol = 0; symbol < n; symbol++)
(h->count[length[symbol]])++;
if (h->count[0] == n)
return 0;
int left = 1;
for (len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= h->count[len];
if (left < 0)
return left;
}
short offs[MAXBITS + 1];
offs[1] = 0;
for (len = 1; len < MAXBITS; len++)
offs[len + 1] = offs[len] + h->count[len];
for (symbol = 0; symbol < n; symbol++)
if (length[symbol] != 0)
h->symbol[offs[length[symbol]]++] = symbol;
return left;
}
static int puff_codes(struct puff_state* s,
const struct puff_huffman* lencode,
const struct puff_huffman* distcode)
{
static const short lens[29] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
static const short lext[29] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
static const short dists[30] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577};
static const short dext[30] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13};
int symbol;
do {
symbol = puff_decode(s, lencode);
if (symbol < 0)
return symbol;
if (symbol < 256) {
if (s->outcnt == s->outlen)
return 1;
if (symbol)
s->out[s->outcnt] = symbol;
s->outcnt++;
} else if (symbol > 256) {
symbol -= 257;
if (symbol >= 29)
return -10;
int len = lens[symbol] + puff_bits(s, lext[symbol]);
symbol = puff_decode(s, distcode);
if (symbol < 0)
return symbol;
unsigned dist = dists[symbol] + puff_bits(s, dext[symbol]);
if (dist > s->outcnt)
return -11;
if (s->outcnt + len > s->outlen)
return 1;
while (len--) {
if (dist <= s->outcnt && s->out[s->outcnt - dist])
s->out[s->outcnt] = s->out[s->outcnt - dist];
s->outcnt++;
}
}
} while (symbol != 256);
return 0;
}
static int puff_fixed(struct puff_state* s)
{
static int virgin = 1;
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
static struct puff_huffman lencode, distcode;
if (virgin) {
lencode.count = lencnt;
lencode.symbol = lensym;
distcode.count = distcnt;
distcode.symbol = distsym;
short lengths[FIXLCODES];
int symbol;
for (symbol = 0; symbol < 144; symbol++)
lengths[symbol] = 8;
for (; symbol < 256; symbol++)
lengths[symbol] = 9;
for (; symbol < 280; symbol++)
lengths[symbol] = 7;
for (; symbol < FIXLCODES; symbol++)
lengths[symbol] = 8;
puff_construct(&lencode, lengths, FIXLCODES);
for (symbol = 0; symbol < MAXDCODES; symbol++)
lengths[symbol] = 5;
puff_construct(&distcode, lengths, MAXDCODES);
virgin = 0;
}
return puff_codes(s, &lencode, &distcode);
}
static int puff_dynamic(struct puff_state* s)
{
static const short order[19] =
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
int nlen = puff_bits(s, 5) + 257;
int ndist = puff_bits(s, 5) + 1;
int ncode = puff_bits(s, 4) + 4;
if (nlen > MAXLCODES || ndist > MAXDCODES)
return -3;
short lengths[MAXCODES];
int index;
for (index = 0; index < ncode; index++)
lengths[order[index]] = puff_bits(s, 3);
for (; index < 19; index++)
lengths[order[index]] = 0;
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
struct puff_huffman lencode = {lencnt, lensym};
int err = puff_construct(&lencode, lengths, 19);
if (err != 0)
return -4;
index = 0;
while (index < nlen + ndist) {
int symbol;
int len;
symbol = puff_decode(s, &lencode);
if (symbol < 0)
return symbol;
if (symbol < 16)
lengths[index++] = symbol;
else {
len = 0;
if (symbol == 16) {
if (index == 0)
return -5;
len = lengths[index - 1];
symbol = 3 + puff_bits(s, 2);
} else if (symbol == 17)
symbol = 3 + puff_bits(s, 3);
else
symbol = 11 + puff_bits(s, 7);
if (index + symbol > nlen + ndist)
return -6;
while (symbol--)
lengths[index++] = len;
}
}
if (lengths[256] == 0)
return -9;
err = puff_construct(&lencode, lengths, nlen);
if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
return -7;
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
struct puff_huffman distcode = {distcnt, distsym};
err = puff_construct(&distcode, lengths + nlen, ndist);
if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
return -8;
return puff_codes(s, &lencode, &distcode);
}
static int puff(
unsigned char* dest,
unsigned long* destlen,
const unsigned char* source,
unsigned long sourcelen)
{
struct puff_state s = {
.out = dest,
.outlen = *destlen,
.outcnt = 0,
.in = source,
.inlen = sourcelen,
.incnt = 0,
.bitbuf = 0,
.bitcnt = 0,
};
int err;
if (setjmp(s.env) != 0)
err = 2;
else {
int last;
do {
last = puff_bits(&s, 1);
int type = puff_bits(&s, 2);
err = type == 0 ? puff_stored(&s) : (type == 1 ? puff_fixed(&s) : (type == 2 ? puff_dynamic(&s) : -1));
if (err != 0)
break;
} while (!last);
}
*destlen = s.outcnt;
return err;
}
//% END CODE DERIVED FROM puff.{c,h}
#define ZLIB_HEADER_WIDTH 2
static int puff_zlib_to_file(const unsigned char* source, unsigned long sourcelen, int dest_fd)
{
if (sourcelen < ZLIB_HEADER_WIDTH)
return 0;
source += ZLIB_HEADER_WIDTH;
sourcelen -= ZLIB_HEADER_WIDTH;
const unsigned long max_destlen = 132 << 20;
void* ret = mmap(0, max_destlen, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
if (ret == MAP_FAILED)
return -1;
unsigned char* dest = (unsigned char*)ret;
unsigned long destlen = max_destlen;
int err = puff(dest, &destlen, source, sourcelen);
if (err) {
munmap(dest, max_destlen);
errno = -err;
return -1;
}
if (write(dest_fd, dest, destlen) != (ssize_t)destlen) {
munmap(dest, max_destlen);
return -1;
}
return munmap(dest, max_destlen);
}
static int setup_loop_device(unsigned char* data, unsigned long size, const char* loopname, int* loopfd_p)
{
int err = 0, loopfd = -1;
int memfd = syscall(__NR_memfd_create, "syzkaller", 0);
if (memfd == -1) {
err = errno;
goto error;
}
if (puff_zlib_to_file(data, size, memfd)) {
err = errno;
goto error_close_memfd;
}
loopfd = open(loopname, O_RDWR);
if (loopfd == -1) {
err = errno;
goto error_close_memfd;
}
if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
if (errno != EBUSY) {
err = errno;
goto error_close_loop;
}
ioctl(loopfd, LOOP_CLR_FD, 0);
usleep(1000);
if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
err = errno;
goto error_close_loop;
}
}
close(memfd);
*loopfd_p = loopfd;
return 0;
error_close_loop:
close(loopfd);
error_close_memfd:
close(memfd);
error:
errno = err;
return -1;
}
static void reset_loop_device(const char* loopname)
{
int loopfd = open(loopname, O_RDWR);
if (loopfd == -1) {
return;
}
if (ioctl(loopfd, LOOP_CLR_FD, 0)) {
}
close(loopfd);
}
static long syz_mount_image(
volatile long fsarg,
volatile long dir,
volatile long flags,
volatile long optsarg,
volatile long change_dir,
volatile unsigned long size,
volatile long image)
{
unsigned char* data = (unsigned char*)image;
int res = -1, err = 0, need_loop_device = !!size;
char* mount_opts = (char*)optsarg;
char* target = (char*)dir;
char* fs = (char*)fsarg;
char* source = NULL;
char loopname[64];
if (need_loop_device) {
int loopfd;
memset(loopname, 0, sizeof(loopname));
snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
if (setup_loop_device(data, size, loopname, &loopfd) == -1)
return -1;
close(loopfd);
source = loopname;
}
mkdir(target, 0777);
char opts[256];
memset(opts, 0, sizeof(opts));
if (strlen(mount_opts) > (sizeof(opts) - 32)) {
}
strncpy(opts, mount_opts, sizeof(opts) - 32);
if (strcmp(fs, "iso9660") == 0) {
flags |= MS_RDONLY;
} else if (strncmp(fs, "ext", 3) == 0) {
bool has_remount_ro = false;
char* remount_ro_start = strstr(opts, "errors=remount-ro");
if (remount_ro_start != NULL) {
char after = *(remount_ro_start + strlen("errors=remount-ro"));
char before = remount_ro_start == opts ? '\0' : *(remount_ro_start - 1);
has_remount_ro = ((before == '\0' || before == ',') && (after == '\0' || after == ','));
}
if (strstr(opts, "errors=panic") || !has_remount_ro)
strcat(opts, ",errors=continue");
} else if (strcmp(fs, "xfs") == 0) {
strcat(opts, ",nouuid");
} else if (strncmp(fs, "gfs2", 4) == 0 && (strstr(opts, "errors=panic") || strstr(opts, "debug"))) {
strcat(opts, ",errors=withdraw");
}
res = mount(source, target, fs, flags, opts);
if (res == -1) {
err = errno;
goto error_clear_loop;
}
res = open(target, O_RDONLY | O_DIRECTORY);
if (res == -1) {
err = errno;
goto error_clear_loop;
}
if (change_dir) {
res = chdir(target);
if (res == -1) {
err = errno;
}
}
error_clear_loop:
if (need_loop_device)
reset_loop_device(loopname);
errno = err;
return res;
}
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
// syz_mount_image$gfs2 arguments: [
// fs: ptr[in, buffer] {
// buffer: {67 66 73 32 00} (length 0x5)
// }
// dir: ptr[in, buffer] {
// buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8)
// }
// flags: mount_flags = 0x208c1b (8 bytes)
// opts: ptr[in, fs_options[gfs2_options]] {
// fs_options[gfs2_options] {
// elems: array[fs_opt_elem[gfs2_options]] {
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// meta: buffer: {6d 65 74 61} (length 0x4)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// loccookie: buffer: {6c 6f 63 63 6f 6f 6b 69 65} (length 0x9)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// noquota: buffer: {6e 6f 71 75 6f 74 61} (length 0x7)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// quota_quantum: fs_opt["quota_quantum", fmt[hex, int32]] {
// name: buffer: {71 75 6f 74 61 5f 71 75 61 6e 74 75 6d} (length 0xd)
// eq: const = 0x3d (1 bytes)
// val: int32 = 0x2 (18 bytes)
// }
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// commit: fs_opt["commit", fmt[hex, int32]] {
// name: buffer: {63 6f 6d 6d 69 74} (length 0x6)
// eq: const = 0x3d (1 bytes)
// val: int32 = 0x5 (18 bytes)
// }
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// noloccookie: buffer: {6e 6f 6c 6f 63 63 6f 6f 6b 69 65} (length 0xb)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// noquota: buffer: {6e 6f 71 75 6f 74 61} (length 0x7)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// suiddir: buffer: {73 75 69 64 64 69 72} (length 0x7)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// acl: buffer: {61 63 6c} (length 0x3)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// rgrplvb: buffer: {72 67 72 70 6c 76 62} (length 0x7)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// quota_on: buffer: {71 75 6f 74 61 3d 6f 6e} (length 0x8)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// statfs_quantum: fs_opt["statfs_quantum", fmt[hex, int32]] {
// name: buffer: {73 74 61 74 66 73 5f 71 75 61 6e 74 75 6d} (length 0xe)
// eq: const = 0x3d (1 bytes)
// val: int32 = 0x5 (18 bytes)
// }
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// quota_quiet: buffer: {71 75 6f 74 61 3d 71 75 69 65 74} (length 0xb)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// norecovery: buffer: {6e 6f 72 65 63 6f 76 65 72 79} (length 0xa)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// barrier: buffer: {62 61 72 72 69 65 72} (length 0x7)
// }
// comma: const = 0x2c (1 bytes)
// }
// fs_opt_elem[gfs2_options] {
// elem: union gfs2_options {
// locktable: fs_opt["locktable", stringnoz] {
// name: buffer: {6c 6f 63 6b 74 61 62 6c 65} (length 0x9)
// eq: const = 0x3d (1 bytes)
// val: buffer: {2e} (length 0x1)
// }
// }
// comma: const = 0x2c (1 bytes)
// }
// }
// common: array[fs_opt_elem[fs_options_common]] {
// }
// null: const = 0x0 (1 bytes)
// }
// }
// chdir: int8 = 0x0 (1 bytes)
// size: len = 0x12754 (8 bytes)
// img: ptr[in, buffer] {
// buffer: (compressed buffer with length 0x12750)
// }
// ]
// returns fd_dir
memcpy((void*)0x200000000000, "gfs2\000", 5);
memcpy((void*)0x200000000100, "./file0\000", 8);
memcpy((void*)0x2000000128c0, "meta", 4);
*(uint8_t*)0x2000000128c4 = 0x2c;
memcpy((void*)0x2000000128c5, "loccookie", 9);
*(uint8_t*)0x2000000128ce = 0x2c;
memcpy((void*)0x2000000128cf, "noquota", 7);
*(uint8_t*)0x2000000128d6 = 0x2c;
memcpy((void*)0x2000000128d7, "quota_quantum", 13);
*(uint8_t*)0x2000000128e4 = 0x3d;
sprintf((char*)0x2000000128e5, "0x%016llx", (long long)2);
*(uint8_t*)0x2000000128f7 = 0x2c;
memcpy((void*)0x2000000128f8, "commit", 6);
*(uint8_t*)0x2000000128fe = 0x3d;
sprintf((char*)0x2000000128ff, "0x%016llx", (long long)5);
*(uint8_t*)0x200000012911 = 0x2c;
memcpy((void*)0x200000012912, "noloccookie", 11);
*(uint8_t*)0x20000001291d = 0x2c;
memcpy((void*)0x20000001291e, "noquota", 7);
*(uint8_t*)0x200000012925 = 0x2c;
memcpy((void*)0x200000012926, "suiddir", 7);
*(uint8_t*)0x20000001292d = 0x2c;
memcpy((void*)0x20000001292e, "acl", 3);
*(uint8_t*)0x200000012931 = 0x2c;
memcpy((void*)0x200000012932, "rgrplvb", 7);
*(uint8_t*)0x200000012939 = 0x2c;
memcpy((void*)0x20000001293a, "quota=on", 8);
*(uint8_t*)0x200000012942 = 0x2c;
memcpy((void*)0x200000012943, "statfs_quantum", 14);
*(uint8_t*)0x200000012951 = 0x3d;
sprintf((char*)0x200000012952, "0x%016llx", (long long)5);
*(uint8_t*)0x200000012964 = 0x2c;
memcpy((void*)0x200000012965, "quota=quiet", 11);
*(uint8_t*)0x200000012970 = 0x2c;
memcpy((void*)0x200000012971, "norecovery", 10);
*(uint8_t*)0x20000001297b = 0x2c;
memcpy((void*)0x20000001297c, "barrier", 7);
*(uint8_t*)0x200000012983 = 0x2c;
memcpy((void*)0x200000012984, "locktable", 9);
*(uint8_t*)0x20000001298d = 0x3d;
memset((void*)0x20000001298e, 46, 1);
*(uint8_t*)0x20000001298f = 0x2c;
*(uint8_t*)0x200000012990 = 0;
memcpy((void*)0x200000000140, "... [truncated large byte array] ...", 75600);
syz_mount_image(/*fs=*/0x200000000000, /*dir=*/0x200000000100, /*flags=MS_SYNCHRONOUS|MS_SILENT|MS_RELATIME|MS_RDONLY|0xc0a*/0x208c1b, /*opts=*/0x2000000128c0, /*chdir=*/0, /*size=*/0x12754, /*img=*/0x200000000140);
return 0;
}
]