aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-02-12 03:52:10 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-12 12:48:29 -0500
commitbc1fc6d88c646ea071de34250552051a63000d70 (patch)
tree37bf115305df3fefce7d0c68b531adfa92085d36
parent79a81aef769f3a188988ad16032ccfc445cfaa13 (diff)
[PATCH] ipc: save the ipc namespace while reading proc files
The problem we were assuming that current->nsproxy->ipc_ns would never change while someone has our file in /proc/sysvipc/ file open. Given that this can change with both unshare and by passing the file descriptor to another process that assumption is occasionally wrong. Therefore this patch causes /proc/sysvipc/* to cache the namespace and increment it's count when we open the file and to decrement the count when we close the file, ensuring consistent operation with no surprises. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Serge E. Hallyn <serue@us.ibm.com> Cc: Herbert Poetzl <herbert@13thfloor.at> Cc: Kirill Korotaev <dev@sw.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--ipc/util.c58
1 files changed, 45 insertions, 13 deletions
diff --git a/ipc/util.c b/ipc/util.c
index 0c97cb746160..115e9aac1366 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -738,14 +738,20 @@ int ipc_parse_version (int *cmd)
738#endif /* __ARCH_WANT_IPC_PARSE_VERSION */ 738#endif /* __ARCH_WANT_IPC_PARSE_VERSION */
739 739
740#ifdef CONFIG_PROC_FS 740#ifdef CONFIG_PROC_FS
741struct ipc_proc_iter {
742 struct ipc_namespace *ns;
743 struct ipc_proc_iface *iface;
744};
745
741static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) 746static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
742{ 747{
743 struct ipc_proc_iface *iface = s->private; 748 struct ipc_proc_iter *iter = s->private;
749 struct ipc_proc_iface *iface = iter->iface;
744 struct kern_ipc_perm *ipc = it; 750 struct kern_ipc_perm *ipc = it;
745 loff_t p; 751 loff_t p;
746 struct ipc_ids *ids; 752 struct ipc_ids *ids;
747 753
748 ids = current->nsproxy->ipc_ns->ids[iface->ids]; 754 ids = iter->ns->ids[iface->ids];
749 755
750 /* If we had an ipc id locked before, unlock it */ 756 /* If we had an ipc id locked before, unlock it */
751 if (ipc && ipc != SEQ_START_TOKEN) 757 if (ipc && ipc != SEQ_START_TOKEN)
@@ -772,12 +778,13 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
772 */ 778 */
773static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) 779static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
774{ 780{
775 struct ipc_proc_iface *iface = s->private; 781 struct ipc_proc_iter *iter = s->private;
782 struct ipc_proc_iface *iface = iter->iface;
776 struct kern_ipc_perm *ipc; 783 struct kern_ipc_perm *ipc;
777 loff_t p; 784 loff_t p;
778 struct ipc_ids *ids; 785 struct ipc_ids *ids;
779 786
780 ids = current->nsproxy->ipc_ns->ids[iface->ids]; 787 ids = iter->ns->ids[iface->ids];
781 788
782 /* 789 /*
783 * Take the lock - this will be released by the corresponding 790 * Take the lock - this will be released by the corresponding
@@ -806,21 +813,23 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
806static void sysvipc_proc_stop(struct seq_file *s, void *it) 813static void sysvipc_proc_stop(struct seq_file *s, void *it)
807{ 814{
808 struct kern_ipc_perm *ipc = it; 815 struct kern_ipc_perm *ipc = it;
809 struct ipc_proc_iface *iface = s->private; 816 struct ipc_proc_iter *iter = s->private;
817 struct ipc_proc_iface *iface = iter->iface;
810 struct ipc_ids *ids; 818 struct ipc_ids *ids;
811 819
812 /* If we had a locked segment, release it */ 820 /* If we had a locked segment, release it */
813 if (ipc && ipc != SEQ_START_TOKEN) 821 if (ipc && ipc != SEQ_START_TOKEN)
814 ipc_unlock(ipc); 822 ipc_unlock(ipc);
815 823
816 ids = current->nsproxy->ipc_ns->ids[iface->ids]; 824 ids = iter->ns->ids[iface->ids];
817 /* Release the lock we took in start() */ 825 /* Release the lock we took in start() */
818 mutex_unlock(&ids->mutex); 826 mutex_unlock(&ids->mutex);
819} 827}
820 828
821static int sysvipc_proc_show(struct seq_file *s, void *it) 829static int sysvipc_proc_show(struct seq_file *s, void *it)
822{ 830{
823 struct ipc_proc_iface *iface = s->private; 831 struct ipc_proc_iter *iter = s->private;
832 struct ipc_proc_iface *iface = iter->iface;
824 833
825 if (it == SEQ_START_TOKEN) 834 if (it == SEQ_START_TOKEN)
826 return seq_puts(s, iface->header); 835 return seq_puts(s, iface->header);
@@ -835,22 +844,45 @@ static struct seq_operations sysvipc_proc_seqops = {
835 .show = sysvipc_proc_show, 844 .show = sysvipc_proc_show,
836}; 845};
837 846
838static int sysvipc_proc_open(struct inode *inode, struct file *file) { 847static int sysvipc_proc_open(struct inode *inode, struct file *file)
848{
839 int ret; 849 int ret;
840 struct seq_file *seq; 850 struct seq_file *seq;
851 struct ipc_proc_iter *iter;
852
853 ret = -ENOMEM;
854 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
855 if (!iter)
856 goto out;
841 857
842 ret = seq_open(file, &sysvipc_proc_seqops); 858 ret = seq_open(file, &sysvipc_proc_seqops);
843 if (!ret) { 859 if (ret)
844 seq = file->private_data; 860 goto out_kfree;
845 seq->private = PDE(inode)->data; 861
846 } 862 seq = file->private_data;
863 seq->private = iter;
864
865 iter->iface = PDE(inode)->data;
866 iter->ns = get_ipc_ns(current->nsproxy->ipc_ns);
867out:
847 return ret; 868 return ret;
869out_kfree:
870 kfree(iter);
871 goto out;
872}
873
874static int sysvipc_proc_release(struct inode *inode, struct file *file)
875{
876 struct seq_file *seq = file->private_data;
877 struct ipc_proc_iter *iter = seq->private;
878 put_ipc_ns(iter->ns);
879 return seq_release_private(inode, file);
848} 880}
849 881
850static struct file_operations sysvipc_proc_fops = { 882static struct file_operations sysvipc_proc_fops = {
851 .open = sysvipc_proc_open, 883 .open = sysvipc_proc_open,
852 .read = seq_read, 884 .read = seq_read,
853 .llseek = seq_lseek, 885 .llseek = seq_lseek,
854 .release = seq_release, 886 .release = sysvipc_proc_release,
855}; 887};
856#endif /* CONFIG_PROC_FS */ 888#endif /* CONFIG_PROC_FS */