aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-06-25 08:48:55 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:20 -0400
commit9c8ef5614da22666e339b125263d315cfaa89109 (patch)
tree860044f1b2c0c6189143b1c9daf263bd8ff5e5e0
parenta4d27e75ffb7b8ecb7eed0c7db0df975525f3fd7 (diff)
[PATCH] fuse: scramble lock owner ID
VFS uses current->files pointer as lock owner ID, and it wouldn't be prudent to expose this value to userspace. So scramble it with XTEA using a per connection random key, known only to the kernel. Only one direction needs to be implemented, since the ID is never sent in the reverse direction. The XTEA algorithm is implemented inline since it's simple enough to do so, and this adds less complexity than if the crypto API were used. Thanks to Jesper Juhl for the idea. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/fuse/file.c29
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/fuse/inode.c2
3 files changed, 25 insertions, 9 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 36f92f181d2f..28aa81eae2cc 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -161,15 +161,25 @@ static int fuse_release(struct inode *inode, struct file *file)
161} 161}
162 162
163/* 163/*
164 * It would be nice to scramble the ID space, so that the value of the 164 * Scramble the ID space with XTEA, so that the value of the files_struct
165 * files_struct pointer is not exposed to userspace. Symmetric crypto 165 * pointer is not exposed to userspace.
166 * functions are overkill, since the inverse function doesn't need to
167 * be implemented (though it does have to exist). Is there something
168 * simpler?
169 */ 166 */
170static inline u64 fuse_lock_owner_id(fl_owner_t id) 167static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
171{ 168{
172 return (unsigned long) id; 169 u32 *k = fc->scramble_key;
170 u64 v = (unsigned long) id;
171 u32 v0 = v;
172 u32 v1 = v >> 32;
173 u32 sum = 0;
174 int i;
175
176 for (i = 0; i < 32; i++) {
177 v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
178 sum += 0x9E3779B9;
179 v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[sum>>11 & 3]);
180 }
181
182 return (u64) v0 + ((u64) v1 << 32);
173} 183}
174 184
175static int fuse_flush(struct file *file, fl_owner_t id) 185static int fuse_flush(struct file *file, fl_owner_t id)
@@ -190,7 +200,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)
190 req = fuse_get_req_nofail(fc, file); 200 req = fuse_get_req_nofail(fc, file);
191 memset(&inarg, 0, sizeof(inarg)); 201 memset(&inarg, 0, sizeof(inarg));
192 inarg.fh = ff->fh; 202 inarg.fh = ff->fh;
193 inarg.lock_owner = fuse_lock_owner_id(id); 203 inarg.lock_owner = fuse_lock_owner_id(fc, id);
194 req->in.h.opcode = FUSE_FLUSH; 204 req->in.h.opcode = FUSE_FLUSH;
195 req->in.h.nodeid = get_node_id(inode); 205 req->in.h.nodeid = get_node_id(inode);
196 req->in.numargs = 1; 206 req->in.numargs = 1;
@@ -644,11 +654,12 @@ static void fuse_lk_fill(struct fuse_req *req, struct file *file,
644 const struct file_lock *fl, int opcode, pid_t pid) 654 const struct file_lock *fl, int opcode, pid_t pid)
645{ 655{
646 struct inode *inode = file->f_dentry->d_inode; 656 struct inode *inode = file->f_dentry->d_inode;
657 struct fuse_conn *fc = get_fuse_conn(inode);
647 struct fuse_file *ff = file->private_data; 658 struct fuse_file *ff = file->private_data;
648 struct fuse_lk_in *arg = &req->misc.lk_in; 659 struct fuse_lk_in *arg = &req->misc.lk_in;
649 660
650 arg->fh = ff->fh; 661 arg->fh = ff->fh;
651 arg->owner = fuse_lock_owner_id(fl->fl_owner); 662 arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
652 arg->lk.start = fl->fl_start; 663 arg->lk.start = fl->fl_start;
653 arg->lk.end = fl->fl_end; 664 arg->lk.end = fl->fl_end;
654 arg->lk.type = fl->fl_type; 665 arg->lk.type = fl->fl_type;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index c862df58da92..0dbf96621841 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -359,6 +359,9 @@ struct fuse_conn {
359 359
360 /** O_ASYNC requests */ 360 /** O_ASYNC requests */
361 struct fasync_struct *fasync; 361 struct fasync_struct *fasync;
362
363 /** Key for lock owner ID scrambling */
364 u32 scramble_key[4];
362}; 365};
363 366
364static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) 367static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e21ef8a3ad30..5ceb8bd7a189 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -16,6 +16,7 @@
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/parser.h> 17#include <linux/parser.h>
18#include <linux/statfs.h> 18#include <linux/statfs.h>
19#include <linux/random.h>
19 20
20MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); 21MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
21MODULE_DESCRIPTION("Filesystem in Userspace"); 22MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -387,6 +388,7 @@ static struct fuse_conn *new_conn(void)
387 fc->bdi.unplug_io_fn = default_unplug_io_fn; 388 fc->bdi.unplug_io_fn = default_unplug_io_fn;
388 fc->reqctr = 0; 389 fc->reqctr = 0;
389 fc->blocked = 1; 390 fc->blocked = 1;
391 get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
390 } 392 }
391 return fc; 393 return fc;
392} 394}