diff options
| -rw-r--r-- | fs/fuse/file.c | 29 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 2 |
3 files changed, 25 insertions, 9 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 36f92f181d..28aa81eae2 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 | */ |
| 170 | static inline u64 fuse_lock_owner_id(fl_owner_t id) | 167 | static 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 | ||
| 175 | static int fuse_flush(struct file *file, fl_owner_t id) | 185 | static 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 c862df58da..0dbf966218 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 | ||
| 364 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) | 367 | static 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 e21ef8a3ad..5ceb8bd7a1 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 | ||
| 20 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); | 21 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); |
| 21 | MODULE_DESCRIPTION("Filesystem in Userspace"); | 22 | MODULE_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 | } |
