Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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.
  • Loading branch information
Linus Torvalds committed Apr 26, 2008
2 parents a929107 + f8f9570 commit bc84e0a
Show file tree
Hide file tree
Showing 16 changed files with 95 additions and 172 deletions.
7 changes: 3 additions & 4 deletions fs/9p/vfs_super.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,11 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
}

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);
}

static const struct super_operations v9fs_super_ops = {
Expand Down
23 changes: 1 addition & 22 deletions fs/binfmt_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0;
struct files_struct *files;
int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0;
struct {
Expand Down Expand Up @@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
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();
if (retval < 0)
goto out_free_fh;
goto out_free_ph;
get_file(bprm->file);
fd_install(elf_exec_fileno = retval, bprm->file);

Expand Down Expand Up @@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval)
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 */
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
Expand Down Expand Up @@ -1016,9 +998,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
kfree(elf_interpreter);
out_free_file:
sys_close(elf_exec_fileno);
out_free_fh:
if (files)
reset_files_struct(current, files);
out_free_ph:
kfree(elf_phdata);
goto out;
Expand Down
18 changes: 1 addition & 17 deletions fs/binfmt_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
char *iname_addr = iname;
int retval;
int fd_binary = -1;
struct files_struct *files = NULL;

retval = -ENOEXEC;
if (!enabled)
Expand All @@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)

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
* interpreter than keep it open and assign descriptor
* to it */
fd_binary = get_unused_fd();
if (fd_binary < 0) {
retval = fd_binary;
goto _unshare;
goto _ret;
}
fd_install(fd_binary, bprm->file);

Expand Down Expand Up @@ -205,20 +196,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval < 0)
goto _error;

if (files) {
put_files_struct(files);
files = NULL;
}
_ret:
return retval;
_error:
if (fd_binary > 0)
sys_close(fd_binary);
bprm->interp_flags = 0;
bprm->interp_data = 0;
_unshare:
if (files)
reset_files_struct(current, files);
goto _ret;
}

Expand Down
10 changes: 0 additions & 10 deletions fs/binfmt_som.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned long som_entry;
struct som_hdr *som_ex;
struct som_exec_auxhdr *hpuxhdr;
struct files_struct *files;

/* Get the exec-header */
som_ex = (struct som_hdr *) bprm->buf;
Expand All @@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
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();
if (retval < 0)
goto out_free;
Expand Down
29 changes: 21 additions & 8 deletions fs/cifs/cifs_dfs_ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,26 @@

static LIST_HEAD(cifs_dfs_automount_list);

/*
* DFS functions
*/
static void cifs_dfs_expire_automounts(struct work_struct *work);
static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
cifs_dfs_expire_automounts);
static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;

static void cifs_dfs_expire_automounts(struct work_struct *work)
{
struct list_head *list = &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 dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
void cifs_dfs_release_automount_timer(void)
{
mark_mounts_for_expiry(&cifs_dfs_automount_list);
mark_mounts_for_expiry(&cifs_dfs_automount_list);
BUG_ON(!list_empty(&cifs_dfs_automount_list));
cancel_delayed_work(&cifs_dfs_automount_task);
flush_scheduled_work();
}

/**
Expand Down Expand Up @@ -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);
switch (err) {
case 0:
dput(nd->path.dentry);
mntput(nd->path.mnt);
path_put(&nd->path);
nd->path.mnt = newmnt;
nd->path.dentry = dget(newmnt->mnt_root);
schedule_delayed_work(&cifs_dfs_automount_task,
cifs_dfs_mountpoint_expiry_timeout);
break;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
Expand Down
10 changes: 3 additions & 7 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,16 +466,11 @@ static struct quotactl_ops cifs_quotactl_ops = {
};
#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;

dfs_shrink_umount_helper(vfsmnt);

if (!(flags & MNT_FORCE))
return;
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
if (cifs_sb == NULL)
return;

Expand Down Expand Up @@ -1100,6 +1095,7 @@ exit_cifs(void)
cFYI(DBG2, ("exit_cifs"));
cifs_proc_clean();
#ifdef CONFIG_CIFS_DFS_UPCALL
cifs_dfs_release_automount_timer();
unregister_key_type(&key_type_dns_resolver);
#endif
#ifdef CONFIG_CIFS_UPCALL
Expand Down
8 changes: 1 addition & 7 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *,
const char *);
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
#ifdef CONFIG_CIFS_DFS_UPCALL
extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
#else
static inline void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
{
}
#endif /* DFS_UPCALL */
extern void cifs_dfs_release_automount_timer(void);
void cifs_proc_init(void);
void cifs_proc_clean(void);

Expand Down
28 changes: 12 additions & 16 deletions fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm)
{
char * name;
int i, ch, retval;
struct files_struct *files;
char tcomm[sizeof(current->comm)];

/*
Expand All @@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm)
if (retval)
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
*/
retval = exec_mmap(bprm->mm);
if (retval)
goto mmap_failed;
goto out;

bprm->mm = NULL; /* We're using it now */

/* This is the point of no return */
put_files_struct(files);

current->sas_ss_sp = current->sas_ss_size = 0;

if (current->euid == current->uid && current->egid == current->gid)
Expand Down Expand Up @@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm)

return 0;

mmap_failed:
reset_files_struct(current, files);
out:
return retval;
}
Expand Down Expand Up @@ -1283,12 +1269,17 @@ int do_execve(char * filename,
struct linux_binprm *bprm;
struct file *file;
unsigned long env_p;
struct files_struct *displaced;
int retval;

retval = unshare_files(&displaced);
if (retval)
goto out_ret;

retval = -ENOMEM;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm)
goto out_ret;
goto out_files;

file = open_exec(filename);
retval = PTR_ERR(file);
Expand Down Expand Up @@ -1343,6 +1334,8 @@ int do_execve(char * filename,
security_bprm_free(bprm);
acct_update_integrals(current);
kfree(bprm);
if (displaced)
put_files_struct(displaced);
return retval;
}

Expand All @@ -1363,6 +1356,9 @@ int do_execve(char * filename,
out_kfree:
kfree(bprm);

out_files:
if (displaced)
reset_files_struct(displaced);
out_ret:
return retval;
}
Expand Down
40 changes: 14 additions & 26 deletions fs/fcntl.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd)
* file_lock held for write.
*/

static int locate_fd(struct files_struct *files,
struct file *file, unsigned int orig_start)
static int locate_fd(unsigned int orig_start, int cloexec)
{
struct files_struct *files = current->files;
unsigned int newfd;
unsigned int start;
int error;
struct fdtable *fdt;

spin_lock(&files->file_lock);

error = -EINVAL;
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
goto out;
Expand Down Expand Up @@ -97,42 +99,28 @@ static int locate_fd(struct files_struct *files,
if (error)
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)
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;

out:
spin_unlock(&files->file_lock);
return error;
}

static int dupfd(struct file *file, unsigned int start, int cloexec)
{
struct files_struct * files = current->files;
struct fdtable *fdt;
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);
int fd = locate_fd(start, cloexec);
if (fd >= 0)
fd_install(fd, file);
} else {
spin_unlock(&files->file_lock);
else
fput(file);
}

return fd;
}
Expand Down
Loading

0 comments on commit bc84e0a

Please sign in to comment.