Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 346335
b: refs/heads/master
c: bf056bf
h: refs/heads/master
i:
  346333: 276d961
  346331: 73d9534
  346327: 9f6b3fd
  346319: fb16227
  346303: b5eb86d
v: v3
  • Loading branch information
Eric W. Biederman committed Nov 20, 2012
1 parent 066bf29 commit 70f3e9b
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 24 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 33d6dce607573b5fd7a43168e0d91221b3ca532b
refs/heads/master: bf056bfa80596a5d14b26b17276a56a0dcb080e5
6 changes: 4 additions & 2 deletions trunk/fs/proc/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static void proc_evict_inode(struct inode *inode)
struct proc_dir_entry *de;
struct ctl_table_header *head;
const struct proc_ns_operations *ns_ops;
void *ns;

truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
Expand All @@ -49,8 +50,9 @@ static void proc_evict_inode(struct inode *inode)
}
/* Release any associated namespace */
ns_ops = PROC_I(inode)->ns_ops;
if (ns_ops && ns_ops->put)
ns_ops->put(PROC_I(inode)->ns);
ns = PROC_I(inode)->ns;
if (ns_ops && ns)
ns_ops->put(ns);
}

static struct kmem_cache * proc_inode_cachep;
Expand Down
169 changes: 148 additions & 21 deletions trunk/fs/proc/namespaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,167 @@ static const struct file_operations ns_file_operations = {
.llseek = no_llseek,
};

static const struct inode_operations ns_inode_operations = {
.setattr = proc_setattr,
};

static int ns_delete_dentry(const struct dentry *dentry)
{
/* Don't cache namespace inodes when not in use */
return 1;
}

static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
{
struct inode *inode = dentry->d_inode;
const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;

return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
ns_ops->name, inode->i_ino);
}

const struct dentry_operations ns_dentry_operations =
{
.d_delete = ns_delete_dentry,
.d_dname = ns_dname,
};

static struct dentry *proc_ns_get_dentry(struct super_block *sb,
struct task_struct *task, const struct proc_ns_operations *ns_ops)
{
struct dentry *dentry, *result;
struct inode *inode;
struct proc_inode *ei;
struct qstr qname = { .name = "", };
void *ns;

ns = ns_ops->get(task);
if (!ns)
return ERR_PTR(-ENOENT);

dentry = d_alloc_pseudo(sb, &qname);
if (!dentry) {
ns_ops->put(ns);
return ERR_PTR(-ENOMEM);
}

inode = new_inode(sb);
if (!inode) {
dput(dentry);
ns_ops->put(ns);
return ERR_PTR(-ENOMEM);
}

ei = PROC_I(inode);
inode->i_ino = get_next_ino();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &ns_inode_operations;
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_fop = &ns_file_operations;
ei->ns_ops = ns_ops;
ei->ns = ns;

d_set_d_op(dentry, &ns_dentry_operations);
result = d_instantiate_unique(dentry, inode);
if (result) {
dput(dentry);
dentry = result;
}

return dentry;
}

static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
struct super_block *sb = inode->i_sb;
struct proc_inode *ei = PROC_I(inode);
struct task_struct *task;
struct dentry *ns_dentry;
void *error = ERR_PTR(-EACCES);

task = get_proc_task(inode);
if (!task)
goto out;

if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out_put_task;

ns_dentry = proc_ns_get_dentry(sb, task, ei->ns_ops);
if (IS_ERR(ns_dentry)) {
error = ERR_CAST(ns_dentry);
goto out_put_task;
}

dput(nd->path.dentry);
nd->path.dentry = ns_dentry;
error = NULL;

out_put_task:
put_task_struct(task);
out:
return error;
}

static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
struct inode *inode = dentry->d_inode;
struct proc_inode *ei = PROC_I(inode);
const struct proc_ns_operations *ns_ops = ei->ns_ops;
struct task_struct *task;
void *ns;
char name[50];
int len = -EACCES;

task = get_proc_task(inode);
if (!task)
goto out;

if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out_put_task;

len = -ENOENT;
ns = ns_ops->get(task);
if (!ns)
goto out_put_task;

snprintf(name, sizeof(name), "%s", ns_ops->name);
len = strlen(name);

if (len > buflen)
len = buflen;
if (copy_to_user(buffer, ns_ops->name, len))
len = -EFAULT;

ns_ops->put(ns);
out_put_task:
put_task_struct(task);
out:
return len;
}

static const struct inode_operations proc_ns_link_inode_operations = {
.readlink = proc_ns_readlink,
.follow_link = proc_ns_follow_link,
.setattr = proc_setattr,
};

static struct dentry *proc_ns_instantiate(struct inode *dir,
struct dentry *dentry, struct task_struct *task, const void *ptr)
{
const struct proc_ns_operations *ns_ops = ptr;
struct inode *inode;
struct proc_inode *ei;
struct dentry *error = ERR_PTR(-ENOENT);
void *ns;

inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
goto out;

ns = ns_ops->get(task);
if (!ns)
goto out_iput;

ei = PROC_I(inode);
inode->i_mode = S_IFREG|S_IRUSR;
inode->i_fop = &ns_file_operations;
ei->ns_ops = ns_ops;
ei->ns = ns;
inode->i_mode = S_IFLNK|S_IRWXUGO;
inode->i_op = &proc_ns_link_inode_operations;
ei->ns_ops = ns_ops;

d_set_d_op(dentry, &pid_dentry_operations);
d_add(dentry, inode);
Expand All @@ -68,9 +207,6 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
error = NULL;
out:
return error;
out_iput:
iput(inode);
goto out;
}

static int proc_ns_fill_cache(struct file *filp, void *dirent,
Expand All @@ -97,10 +233,6 @@ static int proc_ns_dir_readdir(struct file *filp, void *dirent,
if (!task)
goto out_no_task;

ret = -EPERM;
if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out;

ret = 0;
i = filp->f_pos;
switch (i) {
Expand Down Expand Up @@ -160,18 +292,13 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
if (!task)
goto out_no_task;

error = ERR_PTR(-EPERM);
if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out;

last = &ns_entries[ARRAY_SIZE(ns_entries)];
for (entry = ns_entries; entry < last; entry++) {
if (strlen((*entry)->name) != len)
continue;
if (!memcmp(dentry->d_name.name, (*entry)->name, len))
break;
}
error = ERR_PTR(-ENOENT);
if (entry == last)
goto out;

Expand Down

0 comments on commit 70f3e9b

Please sign in to comment.