FreeBSD Bugzilla – Attachment 233146 Details for
Bug 263220
invalid fusefs error numbers can cause kernel crash
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
a fuse daemon that crashes the kernel by setting error=2
futo0.c (text/plain), 9.22 KB, created by
Robert Morris
on 2022-04-11 13:55:25 UTC
(
hide
)
Description:
a fuse daemon that crashes the kernel by setting error=2
Filename:
MIME Type:
Creator:
Robert Morris
Created:
2022-04-11 13:55:25 UTC
Size:
9.22 KB
patch
obsolete
>// >// fuse toy daemon; demo EJUSTRETURN kernel crash. >// >// pkg install fusefs-libs >// cc -I/usr/local/include/fuse -o futo0 futo0.c -L/usr/local/lib -lfuse >// > >#define _FILE_OFFSET_BITS 64 >#define FUSE_USE_VERSION 26 >#include <stdio.h> >#include <stdlib.h> >#include <unistd.h> >#include <fcntl.h> >#include <sys/resource.h> >#include <sys/stat.h> >#include <string.h> >#include <signal.h> >#include <stddef.h> >#include <errno.h> >#include <fuse.h> >#include <fuse_lowlevel.h> >#include <fuse_kernel.h> > >void * >xinit(struct fuse_conn_info *conn) >{ > printf("xinit\n"); > return 0; >} > >int ino = 1; // from last LOOKUP > >struct info { > int parent; // inumber > char *name; > int ino; > int type; // S_IFDIR, S_IFREG >} info[256] = { > { 1, "", 1, S_IFDIR }, >}; > >void >fill_attr(struct fuse_attr *a, int ino) >{ > int ii; > for(ii = 0; info[ii].ino || info[ii].name; ii++) > if(ino == info[ii].ino) > break; > a->ino = ino; > a->mode = info[ii].type | 0777; > a->nlink = 1; > a->size = 1024; > a->blksize = 512; > a->blocks = 2; >} > >int >lookup(int parent, char *name) >{ > for(int ii = 0; info[ii].ino || info[ii].name; ii++){ > if(info[ii].parent == parent && strcmp(name, info[ii].name) == 0){ > return ii; > } > } > return -1; >} > >int >find_free_inum() >{ > for(int ii = 0; ii < 256; ii++){ > if(info[ii].name == 0 && info[ii].ino == 0){ > return ii; > } > } > printf("out of inodes\n"); > exit(1); >} > >void >go() >{ > system("kldload fusefs"); > > int argc = 5; > char *argv[] = { "a.out", "/mnt", "-s", "-d", "-f", 0 }; > struct fuse_operations ops; > memset(&ops, 0, sizeof(ops)); > ops.init = xinit; > char *mountpoint = "/mnt"; > int multithreaded = 0; > int xxxfd = -1; > struct fuse *fuse = fuse_setup(argc, argv, &ops, sizeof(ops), > &mountpoint, &multithreaded, &xxxfd); > if(fuse == 0){ > fprintf(stderr, "fuse_setup() failed\n"); > exit(1); > } > struct fuse_session *se = fuse_get_session(fuse); > struct fuse_chan *ch = fuse_session_next_chan(se, 0); > int fd = fuse_chan_fd(ch); > > while(1){ > char ibuf[1024]; > > int icc = read(fd, ibuf, sizeof(ibuf)); > if(icc <= 0){ > perror("read"); > exit(1); > } > struct fuse_in_header *ih = (struct fuse_in_header *) ibuf; > > char obuf[1024]; > memset(obuf, 0, sizeof(obuf)); > struct fuse_out_header *oh = (struct fuse_out_header *) obuf; > oh->unique = ih->unique; > > if(ih->opcode == FUSE_INIT){ > struct fuse_init_in *in = (struct fuse_init_in *)(ih+1); > printf("init major %d minor %d flags 0x%x\n", in->major, in->minor, in->flags); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_init_out); > struct fuse_init_out *msg = (struct fuse_init_out *)(oh + 1); > msg->major = 7; // version > msg->minor = 28; > msg->max_readahead = 1024; > msg->max_write = 1024; > msg->max_background = 1024; > msg->congestion_threshold = 1024; > msg->flags = 0x7f | FUSE_FLOCK_LOCKS; > } else if(ih->opcode == FUSE_GETATTR){ > struct fuse_getattr_in *in = (struct fuse_getattr_in *)(ih+1); > printf("getattr ino=%x flags=%x\n", ino, in->getattr_flags); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out); > struct fuse_attr_out *msg = (struct fuse_attr_out *)(oh + 1); > msg->attr_valid = 10; > fill_attr(&msg->attr, ino); > } else if(ih->opcode == FUSE_ACCESS){ > struct fuse_access_in *in = (struct fuse_access_in *)(ih+1); > printf("access mask=%x\n", in->mask); > oh->len = sizeof(struct fuse_out_header); > } else if(ih->opcode == FUSE_OPENDIR){ > struct fuse_open_in *in = (struct fuse_open_in *)(ih+1); > printf("opendir flags=%x\n", in->flags); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out); > struct fuse_open_out *msg = (struct fuse_open_out *)(oh + 1); > msg->fh = ino; > msg->open_flags = 0; > } else if(ih->opcode == FUSE_READDIR){ > struct fuse_read_in *in = (struct fuse_read_in *)(ih+1); > printf("readdir fh=%lx offset=%lu size=%d read_flags=%x\n", > in->fh, in->offset, in->size, in->read_flags); > oh->len = sizeof(struct fuse_out_header); > int ii; > for(ii = 0; info[ii].name; ii++){ > if(info[ii].parent == ino){ > break; > } > } > if(in->offset == 0 && info[ii].parent == ino){ > char *content = (char *)(oh + 1); > struct fuse_dirent *dirent = (struct fuse_dirent *) content; > dirent->ino = info[ii].ino; > dirent->off = 1; > dirent->namelen = strlen(info[ii].name); > dirent->type = S_IFREG >> 12; > memcpy(dirent->name, info[ii].name, dirent->namelen); > int sz = FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + dirent->namelen); > oh->len += sz; > } > } else if(ih->opcode == FUSE_STATFS){ > printf("statfs\n"); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_statfs_out); > struct fuse_statfs_out *msg = (struct fuse_statfs_out *)(oh + 1); > msg->st.blocks = 1000000; > msg->st.bfree = 500000; > msg->st.bavail = 500000; > msg->st.files = 1000000; > msg->st.files = 500000; > msg->st.bsize = 512; > msg->st.namelen = 256; > msg->st.frsize = 512; > } else if(ih->opcode == FUSE_LOOKUP){ > char *name= (char *)(ih+1); > printf("lookup %s\n", name); > struct fuse_entry_out *msg = (struct fuse_entry_out *)(oh + 1); > int xino = lookup(ino, name); > if(xino < 0){ > oh->len = sizeof(struct fuse_out_header); > oh->error = ENOENT; // 2 > } else { > ino = xino; > msg->nodeid = ino; > msg->generation = 1; > msg->entry_valid = 100; > msg->attr_valid = 100; > msg->entry_valid_nsec = 100000000; > msg->attr_valid_nsec = 100000000; > fill_attr(&msg->attr, ino); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out); > } > } else if(ih->opcode == FUSE_RELEASEDIR){ > struct fuse_release_in *in = (struct fuse_release_in *)(ih+1); > printf("releasedir fh=%lx flags=%x release_flags=%x\n", > in->fh, in->flags, in->release_flags); > oh->len = sizeof(struct fuse_out_header); > } else if(ih->opcode == FUSE_SETATTR){ > struct fuse_setattr_in *in = (struct fuse_setattr_in *)(ih+1); > printf("setattr ino=%x\n", ino); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out); > struct fuse_attr_out *msg = (struct fuse_attr_out *)(oh + 1); > msg->attr_valid = 10; > fill_attr(&msg->attr, ino); > } else if(ih->opcode == FUSE_FORGET){ > struct fuse_forget_in *in = (struct fuse_forget_in *)(ih+1); > printf("forget nlookup=%lx\n", in->nlookup); > oh = 0; // no reply > } else if(ih->opcode == FUSE_OPEN){ > struct fuse_open_in *in = (struct fuse_open_in *)(ih+1); > printf("open flags=%x\n", in->flags); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out); > struct fuse_open_out *msg = (struct fuse_open_out *)(oh + 1); > msg->fh = ino; > msg->open_flags = 0; > } else if(ih->opcode == FUSE_READ){ > struct fuse_read_in *in = (struct fuse_read_in *)(ih+1); > printf("read fh=%lx offset=%lu size=%d read_flags=%x\n", > in->fh, in->offset, in->size, in->read_flags); > oh->len = sizeof(struct fuse_out_header); > if(in->offset == 0){ > char *content = (char *)(oh + 1); > memcpy(content, "hello\n", 6); > int sz = 6; > oh->len += sz; > } > } else if(ih->opcode == FUSE_FLUSH){ > struct fuse_flush_in *in = (struct fuse_flush_in *)(ih+1); > printf("flush fh=%lx\n", in->fh); > oh->len = sizeof(struct fuse_out_header); > } else if(ih->opcode == FUSE_WRITE){ > struct fuse_write_in *in = (struct fuse_write_in *)(ih+1); > printf("write fh=%lx offset=%lu size=%d\n", in->fh, in->offset, in->size); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out); > struct fuse_write_out *msg = (struct fuse_write_out *)(oh + 1); > msg->size = in->size; > } else if(ih->opcode == FUSE_RELEASE){ > struct fuse_release_in *in = (struct fuse_release_in *)(ih+1); > printf("release fh=%lx flags=%x release_flags=%x\n", > in->fh, in->flags, in->release_flags); > oh->len = sizeof(struct fuse_out_header); > } else if(ih->opcode == FUSE_MKDIR){ > struct fuse_mkdir_in *in = (struct fuse_mkdir_in *)(ih+1); > char *name = (char *)(in + 1); > printf("mkdir name=%s mode=0%o\n", name, in->mode); > oh->len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out); > struct fuse_entry_out *msg = (struct fuse_entry_out *)(oh + 1); > ino = find_free_inum(); > msg->nodeid = ino; > msg->generation = 1; > msg->entry_valid = 100; > msg->attr_valid = 100; > msg->entry_valid_nsec = 100000000; > msg->attr_valid_nsec = 100000000; > fill_attr(&msg->attr, ino); > } else { > printf("unknown op %d\n", ih->opcode); > oh = 0; > } > > if(oh){ > int cc = write(fd, obuf, oh->len); > if(cc <= 0) { perror("write"); } > } > } >} > >int >main() >{ > struct rlimit r; > r.rlim_cur = r.rlim_max = 0; > setrlimit(RLIMIT_CORE, &r); > signal(SIGPIPE, SIG_IGN); > > int pid = fork(); > if(pid < 0){ perror("fork"); exit(1); } > if(pid == 0){ > go(); > exit(1); > } > > sleep(5); > > printf("running touch /mnt/z\n"); > system("touch /mnt/z"); >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 263220
: 233146