mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 01:49:36 +00:00
fuse: Add support for pid namespaces
When the userspace process servicing fuse requests is running in a pid namespace then pids passed via the fuse fd are not being translated into that process' namespace. Translation is necessary for the pid to be useful to that process. Since no use case currently exists for changing namespaces all translations can be done relative to the pid namespace in use when fuse_conn_init() is called. For fuse this translates to mount time, and for cuse this is when /dev/cuse is opened. IO for this connection from another namespace will return errors. Requests from processes whose pid cannot be translated into the target namespace will have a value of 0 for in.h.pid. File locking changes based on previous work done by Eric Biederman. Signed-off-by: Seth Forshee <seth.forshee@canonical.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
095fc40ace
commit
0b6e9ea041
4 changed files with 35 additions and 9 deletions
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/pipe_fs_i.h>
|
#include <linux/pipe_fs_i.h>
|
||||||
#include <linux/swap.h>
|
#include <linux/swap.h>
|
||||||
#include <linux/splice.h>
|
#include <linux/splice.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
|
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
|
||||||
MODULE_ALIAS("devname:fuse");
|
MODULE_ALIAS("devname:fuse");
|
||||||
|
@ -111,11 +112,11 @@ static void __fuse_put_request(struct fuse_req *req)
|
||||||
refcount_dec(&req->count);
|
refcount_dec(&req->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_req_init_context(struct fuse_req *req)
|
static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
|
req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
|
||||||
req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
|
req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
|
||||||
req->in.h.pid = current->pid;
|
req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_set_initialized(struct fuse_conn *fc)
|
void fuse_set_initialized(struct fuse_conn *fc)
|
||||||
|
@ -162,7 +163,7 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fuse_req_init_context(req);
|
fuse_req_init_context(fc, req);
|
||||||
__set_bit(FR_WAITING, &req->flags);
|
__set_bit(FR_WAITING, &req->flags);
|
||||||
if (for_background)
|
if (for_background)
|
||||||
__set_bit(FR_BACKGROUND, &req->flags);
|
__set_bit(FR_BACKGROUND, &req->flags);
|
||||||
|
@ -255,7 +256,7 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
|
||||||
if (!req)
|
if (!req)
|
||||||
req = get_reserved_req(fc, file);
|
req = get_reserved_req(fc, file);
|
||||||
|
|
||||||
fuse_req_init_context(req);
|
fuse_req_init_context(fc, req);
|
||||||
__set_bit(FR_WAITING, &req->flags);
|
__set_bit(FR_WAITING, &req->flags);
|
||||||
__clear_bit(FR_BACKGROUND, &req->flags);
|
__clear_bit(FR_BACKGROUND, &req->flags);
|
||||||
return req;
|
return req;
|
||||||
|
@ -1222,6 +1223,9 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
|
||||||
struct fuse_in *in;
|
struct fuse_in *in;
|
||||||
unsigned reqsize;
|
unsigned reqsize;
|
||||||
|
|
||||||
|
if (task_active_pid_ns(current) != fc->pid_ns)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
spin_lock(&fiq->waitq.lock);
|
spin_lock(&fiq->waitq.lock);
|
||||||
err = -EAGAIN;
|
err = -EAGAIN;
|
||||||
|
@ -1820,6 +1824,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
|
||||||
struct fuse_req *req;
|
struct fuse_req *req;
|
||||||
struct fuse_out_header oh;
|
struct fuse_out_header oh;
|
||||||
|
|
||||||
|
if (task_active_pid_ns(current) != fc->pid_ns)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (nbytes < sizeof(struct fuse_out_header))
|
if (nbytes < sizeof(struct fuse_out_header))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
|
@ -2083,7 +2083,8 @@ static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
return generic_file_mmap(file, vma);
|
return generic_file_mmap(file, vma);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
|
static int convert_fuse_file_lock(struct fuse_conn *fc,
|
||||||
|
const struct fuse_file_lock *ffl,
|
||||||
struct file_lock *fl)
|
struct file_lock *fl)
|
||||||
{
|
{
|
||||||
switch (ffl->type) {
|
switch (ffl->type) {
|
||||||
|
@ -2098,7 +2099,14 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
|
||||||
|
|
||||||
fl->fl_start = ffl->start;
|
fl->fl_start = ffl->start;
|
||||||
fl->fl_end = ffl->end;
|
fl->fl_end = ffl->end;
|
||||||
fl->fl_pid = ffl->pid;
|
|
||||||
|
/*
|
||||||
|
* Convert pid into the caller's pid namespace. If the pid
|
||||||
|
* does not map into the namespace fl_pid will get set to 0.
|
||||||
|
*/
|
||||||
|
rcu_read_lock();
|
||||||
|
fl->fl_pid = pid_vnr(find_pid_ns(ffl->pid, fc->pid_ns));
|
||||||
|
rcu_read_unlock();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2147,7 +2155,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl)
|
||||||
args.out.args[0].value = &outarg;
|
args.out.args[0].value = &outarg;
|
||||||
err = fuse_simple_request(fc, &args);
|
err = fuse_simple_request(fc, &args);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = convert_fuse_file_lock(&outarg.lk, fl);
|
err = convert_fuse_file_lock(fc, &outarg.lk, fl);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -2159,7 +2167,8 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
|
||||||
FUSE_ARGS(args);
|
FUSE_ARGS(args);
|
||||||
struct fuse_lk_in inarg;
|
struct fuse_lk_in inarg;
|
||||||
int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
|
int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
|
||||||
pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
|
struct pid *pid = fl->fl_type != F_UNLCK ? task_tgid(current) : NULL;
|
||||||
|
pid_t pid_nr = pid_nr_ns(pid, fc->pid_ns);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
|
if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
|
||||||
|
@ -2171,7 +2180,10 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
|
||||||
if (fl->fl_flags & FL_CLOSE)
|
if (fl->fl_flags & FL_CLOSE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fuse_lk_fill(&args, file, fl, opcode, pid, flock, &inarg);
|
if (pid && pid_nr == 0)
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg);
|
||||||
err = fuse_simple_request(fc, &args);
|
err = fuse_simple_request(fc, &args);
|
||||||
|
|
||||||
/* locking is restartable */
|
/* locking is restartable */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
#include <linux/xattr.h>
|
#include <linux/xattr.h>
|
||||||
|
#include <linux/pid_namespace.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
|
|
||||||
/** Max number of pages that can be used in a single read request */
|
/** Max number of pages that can be used in a single read request */
|
||||||
|
@ -462,6 +463,9 @@ struct fuse_conn {
|
||||||
/** The group id for this mount */
|
/** The group id for this mount */
|
||||||
kgid_t group_id;
|
kgid_t group_id;
|
||||||
|
|
||||||
|
/** The pid namespace for this mount */
|
||||||
|
struct pid_namespace *pid_ns;
|
||||||
|
|
||||||
/** Maximum read size */
|
/** Maximum read size */
|
||||||
unsigned max_read;
|
unsigned max_read;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/exportfs.h>
|
#include <linux/exportfs.h>
|
||||||
#include <linux/posix_acl.h>
|
#include <linux/posix_acl.h>
|
||||||
|
#include <linux/pid_namespace.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
|
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
|
||||||
MODULE_DESCRIPTION("Filesystem in Userspace");
|
MODULE_DESCRIPTION("Filesystem in Userspace");
|
||||||
|
@ -626,6 +627,7 @@ void fuse_conn_init(struct fuse_conn *fc)
|
||||||
fc->connected = 1;
|
fc->connected = 1;
|
||||||
fc->attr_version = 1;
|
fc->attr_version = 1;
|
||||||
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
|
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
|
||||||
|
fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fuse_conn_init);
|
EXPORT_SYMBOL_GPL(fuse_conn_init);
|
||||||
|
|
||||||
|
@ -634,6 +636,7 @@ void fuse_conn_put(struct fuse_conn *fc)
|
||||||
if (refcount_dec_and_test(&fc->count)) {
|
if (refcount_dec_and_test(&fc->count)) {
|
||||||
if (fc->destroy_req)
|
if (fc->destroy_req)
|
||||||
fuse_request_free(fc->destroy_req);
|
fuse_request_free(fc->destroy_req);
|
||||||
|
put_pid_ns(fc->pid_ns);
|
||||||
fc->release(fc);
|
fc->release(fc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue