Commit bc84e0a1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
  [PATCH] sanitize locate_fd()
  [PATCH] sanitize unshare_files/reset_files_struct
  [PATCH] sanitize handling of shared descriptor tables in failing execve()
  [PATCH] close race in unshare_files()
  [PATCH] restore sane ->umount_begin() API
  cifs: timeout dfs automounts +little fix.
parents a9291072 f8f95702
...@@ -224,11 +224,10 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -224,11 +224,10 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
} }
static void static void
v9fs_umount_begin(struct vfsmount *vfsmnt, int flags) v9fs_umount_begin(struct super_block *sb)
{ {
struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info; struct v9fs_session_info *v9ses = sb->s_fs_info;
if (flags & MNT_FORCE)
v9fs_session_cancel(v9ses); v9fs_session_cancel(v9ses);
} }
......
...@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
unsigned long interp_load_addr = 0; unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data; unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0; unsigned long reloc_func_desc = 0;
struct files_struct *files;
int executable_stack = EXSTACK_DEFAULT; int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0; unsigned long def_flags = 0;
struct { struct {
...@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto out_free_ph; goto out_free_ph;
} }
files = current->files; /* Refcounted so ok */
retval = unshare_files();
if (retval < 0)
goto out_free_ph;
if (files == current->files) {
put_files_struct(files);
files = NULL;
}
/* exec will make our files private anyway, but for the a.out
loader stuff we need to do it earlier */
retval = get_unused_fd(); retval = get_unused_fd();
if (retval < 0) if (retval < 0)
goto out_free_fh; goto out_free_ph;
get_file(bprm->file); get_file(bprm->file);
fd_install(elf_exec_fileno = retval, bprm->file); fd_install(elf_exec_fileno = retval, bprm->file);
...@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval) if (retval)
goto out_free_dentry; goto out_free_dentry;
/* Discard our unneeded old files struct */
if (files) {
put_files_struct(files);
files = NULL;
}
/* OK, This is the point of no return */ /* OK, This is the point of no return */
current->flags &= ~PF_FORKNOEXEC; current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags; current->mm->def_flags = def_flags;
...@@ -1016,9 +998,6 @@ out_free_interp: ...@@ -1016,9 +998,6 @@ out_free_interp:
kfree(elf_interpreter); kfree(elf_interpreter);
out_free_file: out_free_file:
sys_close(elf_exec_fileno); sys_close(elf_exec_fileno);
out_free_fh:
if (files)
reset_files_struct(current, files);
out_free_ph: out_free_ph:
kfree(elf_phdata); kfree(elf_phdata);
goto out; goto out;
......
...@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
char *iname_addr = iname; char *iname_addr = iname;
int retval; int retval;
int fd_binary = -1; int fd_binary = -1;
struct files_struct *files = NULL;
retval = -ENOEXEC; retval = -ENOEXEC;
if (!enabled) if (!enabled)
...@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (fmt->flags & MISC_FMT_OPEN_BINARY) { if (fmt->flags & MISC_FMT_OPEN_BINARY) {
files = current->files;
retval = unshare_files();
if (retval < 0)
goto _ret;
if (files == current->files) {
put_files_struct(files);
files = NULL;
}
/* if the binary should be opened on behalf of the /* if the binary should be opened on behalf of the
* interpreter than keep it open and assign descriptor * interpreter than keep it open and assign descriptor
* to it */ * to it */
fd_binary = get_unused_fd(); fd_binary = get_unused_fd();
if (fd_binary < 0) { if (fd_binary < 0) {
retval = fd_binary; retval = fd_binary;
goto _unshare; goto _ret;
} }
fd_install(fd_binary, bprm->file); fd_install(fd_binary, bprm->file);
...@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval < 0) if (retval < 0)
goto _error; goto _error;
if (files) {
put_files_struct(files);
files = NULL;
}
_ret: _ret:
return retval; return retval;
_error: _error:
...@@ -216,9 +203,6 @@ _error: ...@@ -216,9 +203,6 @@ _error:
sys_close(fd_binary); sys_close(fd_binary);
bprm->interp_flags = 0; bprm->interp_flags = 0;
bprm->interp_data = 0; bprm->interp_data = 0;
_unshare:
if (files)
reset_files_struct(current, files);
goto _ret; goto _ret;
} }
......
...@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned long som_entry; unsigned long som_entry;
struct som_hdr *som_ex; struct som_hdr *som_ex;
struct som_exec_auxhdr *hpuxhdr; struct som_exec_auxhdr *hpuxhdr;
struct files_struct *files;
/* Get the exec-header */ /* Get the exec-header */
som_ex = (struct som_hdr *) bprm->buf; som_ex = (struct som_hdr *) bprm->buf;
...@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out_free; goto out_free;
} }
files = current->files; /* Refcounted so ok */
retval = unshare_files();
if (retval < 0)
goto out_free;
if (files == current->files) {
put_files_struct(files);
files = NULL;
}
retval = get_unused_fd(); retval = get_unused_fd();
if (retval < 0) if (retval < 0)
goto out_free; goto out_free;
......
...@@ -25,14 +25,26 @@ ...@@ -25,14 +25,26 @@
static LIST_HEAD(cifs_dfs_automount_list); static LIST_HEAD(cifs_dfs_automount_list);
/* static void cifs_dfs_expire_automounts(struct work_struct *work);
* DFS functions static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
*/ cifs_dfs_expire_automounts);
static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) static void cifs_dfs_expire_automounts(struct work_struct *work)
{ {
mark_mounts_for_expiry(&cifs_dfs_automount_list); struct list_head *list = &cifs_dfs_automount_list;
mark_mounts_for_expiry(&cifs_dfs_automount_list);
mark_mounts_for_expiry(list);
if (!list_empty(list))
schedule_delayed_work(&cifs_dfs_automount_task,
cifs_dfs_mountpoint_expiry_timeout);
}
void cifs_dfs_release_automount_timer(void)
{
BUG_ON(!list_empty(&cifs_dfs_automount_list));
cancel_delayed_work(&cifs_dfs_automount_task);
flush_scheduled_work();
} }
/** /**
...@@ -261,10 +273,11 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, ...@@ -261,10 +273,11 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist);
switch (err) { switch (err) {
case 0: case 0:
dput(nd->path.dentry); path_put(&nd->path);
mntput(nd->path.mnt);
nd->path.mnt = newmnt; nd->path.mnt = newmnt;
nd->path.dentry = dget(newmnt->mnt_root); nd->path.dentry = dget(newmnt->mnt_root);
schedule_delayed_work(&cifs_dfs_automount_task,
cifs_dfs_mountpoint_expiry_timeout);
break; break;
case -EBUSY: case -EBUSY:
/* someone else made a mount here whilst we were busy */ /* someone else made a mount here whilst we were busy */
......
...@@ -466,16 +466,11 @@ static struct quotactl_ops cifs_quotactl_ops = { ...@@ -466,16 +466,11 @@ static struct quotactl_ops cifs_quotactl_ops = {
}; };
#endif #endif
static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags) static void cifs_umount_begin(struct super_block *sb)
{ {
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
dfs_shrink_umount_helper(vfsmnt);
if (!(flags & MNT_FORCE))
return;
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
if (cifs_sb == NULL) if (cifs_sb == NULL)
return; return;
...@@ -1100,6 +1095,7 @@ exit_cifs(void) ...@@ -1100,6 +1095,7 @@ exit_cifs(void)
cFYI(DBG2, ("exit_cifs")); cFYI(DBG2, ("exit_cifs"));
cifs_proc_clean(); cifs_proc_clean();
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
cifs_dfs_release_automount_timer();
unregister_key_type(&key_type_dns_resolver); unregister_key_type(&key_type_dns_resolver);
#endif #endif
#ifdef CONFIG_CIFS_UPCALL #ifdef CONFIG_CIFS_UPCALL
......
...@@ -104,13 +104,7 @@ extern int mode_to_acl(struct inode *inode, const char *path, __u64); ...@@ -104,13 +104,7 @@ extern int mode_to_acl(struct inode *inode, const char *path, __u64);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *); const char *);
extern int cifs_umount(struct super_block *, struct cifs_sb_info *); extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
#ifdef CONFIG_CIFS_DFS_UPCALL extern void cifs_dfs_release_automount_timer(void);
extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
#else
static inline void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
{
}
#endif /* DFS_UPCALL */
void cifs_proc_init(void); void cifs_proc_init(void);
void cifs_proc_clean(void); void cifs_proc_clean(void);
......
...@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm)
{ {
char * name; char * name;
int i, ch, retval; int i, ch, retval;
struct files_struct *files;
char tcomm[sizeof(current->comm)]; char tcomm[sizeof(current->comm)];
/* /*
...@@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm)
if (retval) if (retval)
goto out; goto out;
/*
* Make sure we have private file handles. Ask the
* fork helper to do the work for us and the exit
* helper to do the cleanup of the old one.
*/
files = current->files; /* refcounted so safe to hold */
retval = unshare_files();
if (retval)
goto out;
/* /*
* Release all of the old mmap stuff * Release all of the old mmap stuff
*/ */
retval = exec_mmap(bprm->mm); retval = exec_mmap(bprm->mm);
if (retval) if (retval)
goto mmap_failed; goto out;
bprm->mm = NULL; /* We're using it now */ bprm->mm = NULL; /* We're using it now */
/* This is the point of no return */ /* This is the point of no return */
put_files_struct(files);
current->sas_ss_sp = current->sas_ss_size = 0; current->sas_ss_sp = current->sas_ss_size = 0;
if (current->euid == current->uid && current->egid == current->gid) if (current->euid == current->uid && current->egid == current->gid)
...@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm)
return 0; return 0;
mmap_failed:
reset_files_struct(current, files);
out: out:
return retval; return retval;
} }
...@@ -1283,12 +1269,17 @@ int do_execve(char * filename, ...@@ -1283,12 +1269,17 @@ int do_execve(char * filename,
struct linux_binprm *bprm; struct linux_binprm *bprm;
struct file *file; struct file *file;
unsigned long env_p; unsigned long env_p;
struct files_struct *displaced;
int retval; int retval;
retval = unshare_files(&displaced);
if (retval)
goto out_ret;
retval = -ENOMEM; retval = -ENOMEM;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm) if (!bprm)
goto out_ret; goto out_files;
file = open_exec(filename); file = open_exec(filename);
retval = PTR_ERR(file); retval = PTR_ERR(file);
...@@ -1343,6 +1334,8 @@ int do_execve(char * filename, ...@@ -1343,6 +1334,8 @@ int do_execve(char * filename,
security_bprm_free(bprm); security_bprm_free(bprm);
acct_update_integrals(current); acct_update_integrals(current);
kfree(bprm); kfree(bprm);
if (displaced)
put_files_struct(displaced);
return retval; return retval;
} }
...@@ -1363,6 +1356,9 @@ out_file: ...@@ -1363,6 +1356,9 @@ out_file:
out_kfree: out_kfree:
kfree(bprm); kfree(bprm);
out_files:
if (displaced)
reset_files_struct(displaced);
out_ret: out_ret:
return retval; return retval;
} }
......
...@@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd) ...@@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd)
* file_lock held for write. * file_lock held for write.
*/ */
static int locate_fd(struct files_struct *files, static int locate_fd(unsigned int orig_start, int cloexec)
struct file *file, unsigned int orig_start)
{ {
struct files_struct *files = current->files;
unsigned int newfd; unsigned int newfd;
unsigned int start; unsigned int start;
int error; int error;
struct fdtable *fdt; struct fdtable *fdt;
spin_lock(&files->file_lock);
error = -EINVAL; error = -EINVAL;
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
goto out; goto out;
...@@ -97,42 +99,28 @@ repeat: ...@@ -97,42 +99,28 @@ repeat:
if (error) if (error)
goto repeat; goto repeat;
/*
* We reacquired files_lock, so we are safe as long as
* we reacquire the fdtable pointer and use it while holding
* the lock, no one can free it during that time.
*/
if (start <= files->next_fd) if (start <= files->next_fd)
files->next_fd = newfd + 1; files->next_fd = newfd + 1;
FD_SET(newfd, fdt->open_fds);
if (cloexec)
FD_SET(newfd, fdt->close_on_exec);
else
FD_CLR(newfd, fdt->close_on_exec);
error = newfd; error = newfd;
out: out:
spin_unlock(&files->file_lock);
return error; return error;
} }
static int dupfd(struct file *file, unsigned int start, int cloexec) static int dupfd(struct file *file, unsigned int start, int cloexec)
{ {
struct files_struct * files = current->files; int fd = locate_fd(start, cloexec);
struct fdtable *fdt; if (fd >= 0)
int fd;
spin_lock(&files->file_lock);
fd = locate_fd(files, file, start);
if (fd >= 0) {
/* locate_fd() may have expanded fdtable, load the ptr */
fdt = files_fdtable(files);
FD_SET(fd, fdt->open_fds);
if (cloexec)
FD_SET(fd, fdt->close_on_exec);
else
FD_CLR(fd, fdt->close_on_exec);
spin_unlock(&files->file_lock);
fd_install(fd, file); fd_install(fd, file);
} else { else
spin_unlock(&files->file_lock);
fput(file); fput(file);
}
return fd; return fd;
} }
......
...@@ -242,10 +242,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, ...@@ -242,10 +242,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
return inode; return inode;
} }
static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) static void fuse_umount_begin(struct super_block *sb)
{ {
if (flags & MNT_FORCE) fuse_abort_conn(get_fuse_conn_super(sb));
fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
} }
static void fuse_send_destroy(struct fuse_conn *fc) static void fuse_send_destroy(struct fuse_conn *fc)
......
...@@ -1061,10 +1061,11 @@ static int do_umount(struct vfsmount *mnt, int flags) ...@@ -1061,10 +1061,11 @@ static int do_umount(struct vfsmount *mnt, int flags)
* about for the moment. * about for the moment.
*/ */
if (flags & MNT_FORCE && sb->s_op->umount_begin) {
lock_kernel(); lock_kernel();
if (sb->s_op->umount_begin) sb->s_op->umount_begin(sb);
sb->s_op->umount_begin(mnt, flags);
unlock_kernel(); unlock_kernel();
}
/* /*
* No sense to grab the lock for this test, but test itself looks * No sense to grab the lock for this test, but test itself looks
......
...@@ -198,7 +198,7 @@ static match_table_t nfs_secflavor_tokens = { ...@@ -198,7 +198,7 @@ static match_table_t nfs_secflavor_tokens = {
}; };
static void nfs_umount_begin(struct vfsmount *, int); static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct dentry *, struct kstatfs *); static int nfs_statfs(struct dentry *, struct kstatfs *);
static int nfs_show_options(struct seq_file *, struct vfsmount *); static int nfs_show_options(struct seq_file *, struct vfsmount *);
static int nfs_show_stats(struct seq_file *, struct vfsmount *); static int nfs_show_stats(struct seq_file *, struct vfsmount *);
...@@ -647,13 +647,11 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) ...@@ -647,13 +647,11 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
* Begin unmount by attempting to remove all automounted mountpoints we added * Begin unmount by attempting to remove all automounted mountpoints we added
* in response to xdev traversals and referrals * in response to xdev traversals and referrals
*/ */
static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) static void nfs_umount_begin(struct super_block *sb)
{ {
struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); struct nfs_server *server = NFS_SB(sb);
struct rpc_clnt *rpc; struct rpc_clnt *rpc;
if (!(flags & MNT_FORCE))
return;
/* -EIO all pending I/O */ /* -EIO all pending I/O */
rpc = server->client_acl; rpc = server->client_acl;
if (!IS_ERR(rpc)) if (!IS_ERR(rpc))
......
...@@ -117,7 +117,8 @@ struct task_struct; ...@@ -117,7 +117,8 @@ struct task_struct;
struct files_struct *get_files_struct(struct task_struct *); struct files_struct *get_files_struct(struct task_struct *);
void put_files_struct(struct files_struct *fs); void put_files_struct(struct files_struct *fs);
void reset_files_struct(struct task_struct *, struct files_struct *); void reset_files_struct(struct files_struct *);
int unshare_files(struct files_struct **);
extern struct kmem_cache *files_cachep; extern struct kmem_cache *files_cachep;
......
...@@ -1309,7 +1309,7 @@ struct super_operations { ...@@ -1309,7 +1309,7 @@ struct super_operations {
int (*statfs) (struct dentry *, struct kstatfs *); int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *); int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *); void (*clear_inode) (struct inode *);
void (*umount_begin) (struct vfsmount *, int); void (*umount_begin) (struct super_block *);
int (*show_options)(struct seq_file *, struct vfsmount *); int (*show_options)(struct seq_file *, struct vfsmount *);
int (*show_stats)(struct seq_file *, struct vfsmount *); int (*show_stats)(struct seq_file *, struct vfsmount *);
...@@ -2034,9 +2034,6 @@ static inline ino_t parent_ino(struct dentry *dentry) ...@@ -2034,9 +2034,6 @@ static inline ino_t parent_ino(struct dentry *dentry)
return res; return res;
} }
/* kernel/fork.c */
extern int unshare_files(void);
/* Transaction based IO helpers */ /* Transaction based IO helpers */
/* /*
......
...@@ -507,10 +507,9 @@ void put_files_struct(struct files_struct *files) ...@@ -507,10 +507,9 @@ void put_files_struct(struct files_struct *files)
} }
} }
EXPORT_SYMBOL(put_files_struct); void reset_files_struct(struct files_struct *files)
void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
{ {
struct task_struct *tsk = current;
struct files_struct *old; struct files_struct *old;
old = tsk->files; old = tsk->files;
...@@ -519,7 +518,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files) ...@@ -519,7 +518,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
task_unlock(tsk); task_unlock(tsk);
put_files_struct(old); put_files_struct(old);
} }
EXPORT_SYMBOL(reset_files_struct);
void exit_files(struct task_struct *tsk) void exit_files(struct task_struct *tsk)
{ {
......
...@@ -805,12 +805,6 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) ...@@ -805,12 +805,6 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
goto out; goto out;
} }
/*
* Note: we may be using current for both targets (See exec.c)
* This works because we cache current->files (old) as oldf. Don't
* break this.
*/
tsk->files = NULL;
newf = dup_fd(oldf, &error); newf = dup_fd(oldf, &error);
if (!newf) if (!newf)
goto out; goto out;
...@@ -846,34 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk) ...@@ -846,34 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
return 0; return 0;
} }
/*
* Helper to unshare the files of the current task.
* We don't want to expose copy_files internals to
* the exec layer of the kernel.
*/
int unshare_files(void)
{
struct files_struct *files = current->files;
int rc;
BUG_ON(!files);
/* This can race but the race causes us to copy when we don't
need to and drop the copy */
if(atomic_read(&files->count) == 1)
{
atomic_inc(&files->count);
return 0;
}
rc = copy_files(0, current);
if(rc)
current->files = files;
return rc;
}
EXPORT_SYMBOL(unshare_files);
static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
{ {
struct sighand_struct *sig; struct sighand_struct *sig;
...@@ -1811,3 +1777,27 @@ bad_unshare_cleanup_thread: ...@@ -1811,3 +1777,27 @@ bad_unshare_cleanup_thread:
bad_unshare_out: bad_unshare_out:
return err; return err;
} }
/*
* Helper to unshare the files of the current task.
* We don't want to expose copy_files internals to
* the exec layer of the kernel.
*/
int unshare_files(struct files_struct **displaced)
{
struct task_struct *task = current;
struct files_struct *copy;
int error;
error = unshare_fd(CLONE_FILES, &copy);
if (error || !copy) {
*displaced = NULL;
return error;
}
*displaced = task->files;
task_lock(task);
task->files = copy;
task_unlock(task);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment