From: Miklos Szeredi Date: Thu, 20 Dec 2001 15:38:05 +0000 (+0000) Subject: permission checking implemented X-Git-Tag: fuse_0_95~7 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=fe25def3344095825738deba119e1400b8e2315f;p=qemu-gpiodev%2Flibfuse.git permission checking implemented --- diff --git a/BUGS b/BUGS index 3706264..5fdce02 100644 --- a/BUGS +++ b/BUGS @@ -1,8 +1,5 @@ - It is allowed to mount a directory on a non-directory. -- When a non-directory is mounted the root inode is not filled in, only at - the first getattr - - I want really low priority for my cached pages. Can they start out 'old' so they will be thrown out on the first oportunity? diff --git a/ChangeLog b/ChangeLog index cfa7aef..cf7aaa8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,36 @@ -2001-11-09 Miklos Szeredi +2001-12-20 Miklos Szeredi + + * Added function fuse_get_context() to library API (inspired by + patch from Matt Ryan) + + * Added flags to fusermount and to kernel interface to control + permission checking - * Started ChangeLog + * Integrated fuse_set_operations() into fuse_new() + +2001-12-08 Miklos Szeredi + + * Applied header protection + extern "C" patch by Roland + Bauerschmidt + +2001-12-02 Miklos Szeredi + + * Added perl bindings by Mark Glines + +2001-11-21 Miklos Szeredi + + * Cleaned up way of mounting simple filesystems. + + * fuse_main() helper function added + +2001-11-18 Miklos Szeredi + + * Optimized read/write operations, so that minimal copying of data + is done + +2001-11-14 Miklos Szeredi + + * Python bindings by Jeff Epler added 2001-11-13 Miklos Szeredi @@ -9,7 +39,6 @@ * FS blocksize is set to PAGE_CACHE_SIZE, blksize attribute from userspace is ignored -2001-11-14 Miklos Szeredi - - * Python bindings by Jeff Epler added +2001-11-09 Miklos Szeredi + * Started ChangeLog diff --git a/TODO b/TODO index 2942e4e..fbf6d70 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,5 @@ - Better (but not too complex) library interface for open/read/write/close - - Permission checking for users other then the owner of the mount - - Integrate (parts of) fusermount into mount(8) - Statfs operation diff --git a/include/linux/fuse.h b/include/linux/fuse.h index fd5ef9c..53cb3f0 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -9,7 +9,7 @@ /* This file defines the kernel interface of FUSE */ /** Version number of this interface */ -#define FUSE_KERNEL_VERSION 1 +#define FUSE_KERNEL_VERSION 2 /** The inode number of the root indode */ #define FUSE_ROOT_INO 1 @@ -35,6 +35,17 @@ struct fuse_mount_data { unsigned int flags; }; +/* FUSE mount flags: */ + +/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem +module will check permissions based on the file mode. Otherwise no +permission checking is done in the kernel */ +#define FUSE_DEFAULT_PERMISSIONS (1 << 0) + +/** If the FUSE_ALLOW_OTHER flag is given, then not only the user + doing the mount will be allowed to access the filesystem */ +#define FUSE_ALLOW_OTHER (1 << 1) + struct fuse_attr { unsigned int mode; unsigned int nlink; @@ -149,6 +160,8 @@ struct fuse_in_header { int unique; enum fuse_opcode opcode; unsigned long ino; + unsigned int uid; + unsigned int gid; }; struct fuse_out_header { diff --git a/kernel/dir.c b/kernel/dir.c index a3f1485..7068d37 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -315,29 +315,14 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, return out.h.error; } -static int fuse_permission(struct inode *inode, int mask) -{ - struct fuse_conn *fc = INO_FC(inode); - - /* (too) simple protection */ - if(current->fsuid == fc->uid) - return 0; - else - return -EACCES; -} -static int fuse_revalidate(struct dentry *entry) +int fuse_getattr(struct inode *inode) { - struct inode *inode = entry->d_inode; struct fuse_conn *fc = INO_FC(inode); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_getattr_out arg; - if(inode->i_ino != FUSE_ROOT_INO && - time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) - return 0; - in.h.opcode = FUSE_GETATTR; in.h.ino = inode->i_ino; out.numargs = 1; @@ -351,6 +336,57 @@ static int fuse_revalidate(struct dentry *entry) return out.h.error; } +static int fuse_revalidate(struct dentry *entry) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = INO_FC(inode); + + if(inode->i_ino == FUSE_ROOT_INO) { + if(!(fc->flags & FUSE_ALLOW_OTHER) + && current->fsuid != fc->uid) + return -EACCES; + } + else if(time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) + return 0; + + return fuse_getattr(inode); +} + +static int fuse_permission(struct inode *inode, int mask) +{ + struct fuse_conn *fc = INO_FC(inode); + + if(!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid) + return -EACCES; + else if(fc->flags & FUSE_DEFAULT_PERMISSIONS) { + int err = vfs_permission(inode, mask); + + /* If permission is denied, try to refresh file + attributes. This is also needed, because the root + node will at first have no permissions */ + + if(err == -EACCES) { + err = fuse_getattr(inode); + if(!err) + err = vfs_permission(inode, mask); + } + + /* FIXME: Need some mechanism to revoke permissions: + currently if the filesystem suddenly changes the + file mode, we will not be informed abot that, and + continue to allow access to the file/directory. + + This is actually not so grave, since the user can + simply keep access to the file/directory anyway by + keeping it open... */ + + return err; + } + else + return 0; +} + + static int parse_dirfile(char *buf, size_t nbytes, struct file *file, void *dstbuf, filldir_t filldir) { diff --git a/kernel/file.c b/kernel/file.c index b7cb2f4..0622e51 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -17,6 +17,14 @@ static int fuse_open(struct inode *inode, struct file *file) struct fuse_out out = FUSE_OUT_INIT; struct fuse_open_in inarg; + /* If opening the root node, no lookup has been performed on + it, so the attributes must be refreshed */ + if(inode->i_ino == FUSE_ROOT_INO) { + int err = fuse_getattr(inode); + if(err) + return err; + } + memset(&inarg, 0, sizeof(inarg)); inarg.flags = file->f_flags & ~O_EXCL; diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 27d8eb3..262e05d 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -77,7 +77,7 @@ struct fuse_out { struct fuse_out_arg args[3]; }; -#define FUSE_IN_INIT { {0, 0, 0}, 0} +#define FUSE_IN_INIT { {0, 0, 0, current->fsuid, current->fsgid}, 0} #define FUSE_OUT_INIT { {0, 0}, 0, 0} /** @@ -178,6 +178,11 @@ void request_send(struct fuse_conn *fc, struct fuse_in *in, */ int request_send_noreply(struct fuse_conn *fc, struct fuse_in *in); +/** + * Get the attributes of a file + */ +int fuse_getattr(struct inode *inode); + /* * Local Variables: * indent-tabs-mode: t diff --git a/kernel/inode.c b/kernel/inode.c index 7d211cb..7fc5cfe 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -32,6 +32,7 @@ static void fuse_clear_inode(struct inode *inode) in = kmalloc(sizeof(struct fuse_in), GFP_NOFS); if(!in) return; + memset(in, 0, sizeof(struct fuse_in)); inarg = kmalloc(sizeof(struct fuse_forget_in), GFP_NOFS); if(!inarg) diff --git a/lib/fuse.c b/lib/fuse.c index 0a0b40a..541014f 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -781,6 +781,7 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf; void *inarg = cmd->buf + sizeof(struct fuse_in_header); size_t argsize; + struct fuse_context *ctx = fuse_get_context(f); dec_avail(f); @@ -789,6 +790,9 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) in->opcode, in->ino, cmd->buflen); fflush(stdout); } + + ctx->uid = in->uid; + ctx->gid = in->gid; argsize = cmd->buflen - sizeof(struct fuse_in_header); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 604c297..d587af1 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -37,6 +37,7 @@ struct fuse { int numavail; struct fuse_context *(*getcontext)(struct fuse *); struct fuse_context context; + pthread_key_t context_key; }; struct fuse_dirhandle { diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index 4534d0f..b8756ac 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -69,9 +69,28 @@ static void start_thread(struct fuse_worker *w) pthread_detach(thrid); } +static struct fuse_context *mt_getcontext(struct fuse *f) +{ + struct fuse_context *ctx; + + ctx = (struct fuse_context *) pthread_getspecific(f->context_key); + if(ctx == NULL) { + ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context)); + pthread_setspecific(f->context_key, ctx); + } + + return ctx; +} + +static void mt_freecontext(void *data) +{ + free(data); +} + void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data) { struct fuse_worker *w; + int res; w = malloc(sizeof(struct fuse_worker)); w->f = f; @@ -79,6 +98,12 @@ void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data) w->proc = proc; f->numworker = 1; + res = pthread_key_create(&f->context_key, mt_freecontext); + if(res != 0) { + fprintf(stderr, "Failed to create thread specific key\n"); + exit(1); + } + f->getcontext = mt_getcontext; do_work(w); } diff --git a/util/fusermount.c b/util/fusermount.c index ee51269..94f435f 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -264,7 +264,7 @@ static void restore_privs() } static int do_mount(const char *dev, const char *mnt, const char *type, - mode_t rootmode, int fd) + mode_t rootmode, int fd, int fuseflags) { int res; struct fuse_mount_data data; @@ -282,7 +282,7 @@ static int do_mount(const char *dev, const char *mnt, const char *type, data.fd = fd; data.rootmode = rootmode; data.uid = getuid(); - data.flags = 0; + data.flags = fuseflags; res = mount(dev, mnt, type, flags, &data); if(res == -1) @@ -332,7 +332,7 @@ static int check_perm(const char *mnt, struct stat *stbuf) return 0; } -static int mount_fuse(const char *mnt) +static int mount_fuse(const char *mnt, int flags) { int res; int fd; @@ -364,7 +364,7 @@ static int mount_fuse(const char *mnt) return -1; } - res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd); + res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd, flags); if(res == -1) return -1; @@ -401,7 +401,9 @@ static void usage() "%s: [options] mountpoint [program [args ...]]\n" "Options:\n" " -h print help\n" - " -u unmount\n", + " -u unmount\n" + " -p check default permissions on files\n" + " -x allow other users to access the files (only for root)\n", progname); exit(1); } @@ -419,6 +421,7 @@ int main(int argc, char *argv[]) char mypath[PATH_MAX]; char *unmount_cmd; char verstr[128]; + int flags = 0; progname = argv[0]; @@ -435,6 +438,19 @@ int main(int argc, char *argv[]) unmount = 1; break; + case 'p': + flags |= FUSE_DEFAULT_PERMISSIONS; + break; + + case 'x': + if(getuid() != 0) { + fprintf(stderr, "%s: option %s is allowed only for root\n", + progname, argv[a]); + exit(1); + } + flags |= FUSE_ALLOW_OTHER; + break; + default: fprintf(stderr, "%s: Unknown option %s\n", progname, argv[a]); exit(1); @@ -474,7 +490,7 @@ int main(int argc, char *argv[]) userprog = argv + a; numargs = argc - a; - fd = mount_fuse(mnt); + fd = mount_fuse(mnt, flags); if(fd == -1) exit(1);