aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hostfs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-06-06 23:16:34 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-09 16:48:14 -0400
commite9193059b1b3733695d5b80e667778311695aa73 (patch)
tree658862931873ef6155ebe2172235bb408632a603 /fs/hostfs
parentc103135c14e03fc9a9e5f0adc01df9ad272cf2a1 (diff)
hostfs: fix races in dentry_name() and inode_name()
calculating size, then doing allocation, then filling the path is a Bad Idea(tm), since the ancestors can be renamed, leading to buffer overrun. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/hostfs')
-rw-r--r--fs/hostfs/hostfs_kern.c106
1 files changed, 60 insertions, 46 deletions
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 10bb71b1548b..79783a0b2f4d 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -90,44 +90,58 @@ __uml_setup("hostfs=", hostfs_args,
90); 90);
91#endif 91#endif
92 92
93static char *dentry_name(struct dentry *dentry) 93static char *__dentry_name(struct dentry *dentry, char *name)
94{ 94{
95 struct dentry *parent; 95 char *p = __dentry_path(dentry, name, PATH_MAX);
96 char *root, *name; 96 char *root;
97 int len; 97 size_t len;
98 98
99 len = 0; 99 spin_unlock(&dcache_lock);
100 parent = dentry;
101 while (parent->d_parent != parent) {
102 len += parent->d_name.len + 1;
103 parent = parent->d_parent;
104 }
105 100
106 root = parent->d_sb->s_fs_info; 101 root = dentry->d_sb->s_fs_info;
107 len += strlen(root); 102 len = strlen(root);
108 name = kmalloc(len + 1, GFP_KERNEL); 103 if (IS_ERR(p)) {
109 if (name == NULL) 104 __putname(name);
110 return NULL; 105 return NULL;
111
112 name[len] = '\0';
113 parent = dentry;
114 while (parent->d_parent != parent) {
115 len -= parent->d_name.len + 1;
116 name[len] = '/';
117 strncpy(&name[len + 1], parent->d_name.name,
118 parent->d_name.len);
119 parent = parent->d_parent;
120 } 106 }
121 strncpy(name, root, strlen(root)); 107 strncpy(name, root, PATH_MAX);
108 if (len > p - name) {
109 __putname(name);
110 return NULL;
111 }
112 if (p > name + len) {
113 char *s = name + len;
114 while ((*s++ = *p++) != '\0')
115 ;
116 }
122 return name; 117 return name;
123} 118}
124 119
120static char *dentry_name(struct dentry *dentry)
121{
122 char *name = __getname();
123 if (!name)
124 return NULL;
125
126 spin_lock(&dcache_lock);
127 return __dentry_name(dentry, name); /* will unlock */
128}
129
125static char *inode_name(struct inode *ino) 130static char *inode_name(struct inode *ino)
126{ 131{
127 struct dentry *dentry; 132 struct dentry *dentry;
133 char *name = __getname();
134 if (!name)
135 return NULL;
128 136
129 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); 137 spin_lock(&dcache_lock);
130 return dentry_name(dentry); 138 if (list_empty(&ino->i_dentry)) {
139 spin_unlock(&dcache_lock);
140 __putname(name);
141 return NULL;
142 }
143 dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias);
144 return __dentry_name(dentry, name); /* will unlock */
131} 145}
132 146
133static char *follow_link(char *link) 147static char *follow_link(char *link)
@@ -272,7 +286,7 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
272 if (name == NULL) 286 if (name == NULL)
273 return -ENOMEM; 287 return -ENOMEM;
274 dir = open_dir(name, &error); 288 dir = open_dir(name, &error);
275 kfree(name); 289 __putname(name);
276 if (dir == NULL) 290 if (dir == NULL)
277 return -error; 291 return -error;
278 next = file->f_pos; 292 next = file->f_pos;
@@ -318,7 +332,7 @@ int hostfs_file_open(struct inode *ino, struct file *file)
318 return -ENOMEM; 332 return -ENOMEM;
319 333
320 fd = open_file(name, r, w, append); 334 fd = open_file(name, r, w, append);
321 kfree(name); 335 __putname(name);
322 if (fd < 0) 336 if (fd < 0)
323 return fd; 337 return fd;
324 FILE_HOSTFS_I(file)->fd = fd; 338 FILE_HOSTFS_I(file)->fd = fd;
@@ -532,7 +546,7 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
532 else 546 else
533 error = read_name(inode, name); 547 error = read_name(inode, name);
534 548
535 kfree(name); 549 __putname(name);
536 if (error) 550 if (error)
537 goto out_put; 551 goto out_put;
538 552
@@ -567,7 +581,7 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
567 581
568 err = read_name(inode, name); 582 err = read_name(inode, name);
569 583
570 kfree(name); 584 __putname(name);
571 if (err == -ENOENT) { 585 if (err == -ENOENT) {
572 iput(inode); 586 iput(inode);
573 inode = NULL; 587 inode = NULL;
@@ -594,12 +608,12 @@ int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
594 return -ENOMEM; 608 return -ENOMEM;
595 to_name = dentry_name(to); 609 to_name = dentry_name(to);
596 if (to_name == NULL) { 610 if (to_name == NULL) {
597 kfree(from_name); 611 __putname(from_name);
598 return -ENOMEM; 612 return -ENOMEM;
599 } 613 }
600 err = link_file(to_name, from_name); 614 err = link_file(to_name, from_name);
601 kfree(from_name); 615 __putname(from_name);
602 kfree(to_name); 616 __putname(to_name);
603 return err; 617 return err;
604} 618}
605 619
@@ -614,7 +628,7 @@ int hostfs_unlink(struct inode *ino, struct dentry *dentry)
614 return -EPERM; 628 return -EPERM;
615 629
616 err = unlink_file(file); 630 err = unlink_file(file);
617 kfree(file); 631 __putname(file);
618 return err; 632 return err;
619} 633}
620 634
@@ -626,7 +640,7 @@ int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
626 if ((file = dentry_name(dentry)) == NULL) 640 if ((file = dentry_name(dentry)) == NULL)
627 return -ENOMEM; 641 return -ENOMEM;
628 err = make_symlink(file, to); 642 err = make_symlink(file, to);
629 kfree(file); 643 __putname(file);
630 return err; 644 return err;
631} 645}
632 646
@@ -638,7 +652,7 @@ int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
638 if ((file = dentry_name(dentry)) == NULL) 652 if ((file = dentry_name(dentry)) == NULL)
639 return -ENOMEM; 653 return -ENOMEM;
640 err = do_mkdir(file, mode); 654 err = do_mkdir(file, mode);
641 kfree(file); 655 __putname(file);
642 return err; 656 return err;
643} 657}
644 658
@@ -650,7 +664,7 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
650 if ((file = dentry_name(dentry)) == NULL) 664 if ((file = dentry_name(dentry)) == NULL)
651 return -ENOMEM; 665 return -ENOMEM;
652 err = do_rmdir(file); 666 err = do_rmdir(file);
653 kfree(file); 667 __putname(file);
654 return err; 668 return err;
655} 669}
656 670
@@ -673,13 +687,13 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
673 687
674 init_special_inode(inode, mode, dev); 688 init_special_inode(inode, mode, dev);
675 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); 689 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
676 if (err) 690 if (!err)
677 goto out_free; 691 goto out_free;
678 692
679 err = read_name(inode, name); 693 err = read_name(inode, name);
694 __putname(name);
680 if (err) 695 if (err)
681 goto out_put; 696 goto out_put;
682 kfree(name);
683 if (err) 697 if (err)
684 goto out_put; 698 goto out_put;
685 699
@@ -687,7 +701,7 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
687 return 0; 701 return 0;
688 702
689 out_free: 703 out_free:
690 kfree(name); 704 __putname(name);
691 out_put: 705 out_put:
692 iput(inode); 706 iput(inode);
693 out: 707 out:
@@ -703,12 +717,12 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
703 if ((from_name = dentry_name(from)) == NULL) 717 if ((from_name = dentry_name(from)) == NULL)
704 return -ENOMEM; 718 return -ENOMEM;
705 if ((to_name = dentry_name(to)) == NULL) { 719 if ((to_name = dentry_name(to)) == NULL) {
706 kfree(from_name); 720 __putname(from_name);
707 return -ENOMEM; 721 return -ENOMEM;
708 } 722 }
709 err = rename_file(from_name, to_name); 723 err = rename_file(from_name, to_name);
710 kfree(from_name); 724 __putname(from_name);
711 kfree(to_name); 725 __putname(to_name);
712 return err; 726 return err;
713} 727}
714 728
@@ -729,7 +743,7 @@ int hostfs_permission(struct inode *ino, int desired)
729 err = 0; 743 err = 0;
730 else 744 else
731 err = access_file(name, r, w, x); 745 err = access_file(name, r, w, x);
732 kfree(name); 746 __putname(name);
733 if (!err) 747 if (!err)
734 err = generic_permission(ino, desired, NULL); 748 err = generic_permission(ino, desired, NULL);
735 return err; 749 return err;
@@ -790,7 +804,7 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
790 if (name == NULL) 804 if (name == NULL)
791 return -ENOMEM; 805 return -ENOMEM;
792 err = set_attr(name, &attrs, fd); 806 err = set_attr(name, &attrs, fd);
793 kfree(name); 807 __putname(name);
794 if (err) 808 if (err)
795 return err; 809 return err;
796 810
@@ -845,7 +859,7 @@ static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
845 int err = hostfs_do_readlink(path, link, PATH_MAX); 859 int err = hostfs_do_readlink(path, link, PATH_MAX);
846 if (err == PATH_MAX) 860 if (err == PATH_MAX)
847 err = -E2BIG; 861 err = -E2BIG;
848 kfree(path); 862 __putname(path);
849 } 863 }
850 if (err < 0) { 864 if (err < 0) {
851 __putname(link); 865 __putname(link);