]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/464a925d73f1 |
2 | # HG changeset 863 patch | |
3 | # User Keir Fraser <keir.fraser@citrix.com> | |
4 | # Date 1239969802 -3600 | |
5 | # Node ID 464a925d73f141d8ca568026ee2e6635489affa2 | |
6 | # Parent dfd2adc5874021b52c13d317df1f55b46ec38e3d | |
7 | Subject: blktap: don't access deallocated data | |
8 | References: bnc#484210, bnc#485652 | |
9 | Patch-mainline: obsolete | |
10 | ||
11 | Dereferencing filp->private_data->vma in the file_operations.release | |
12 | actor isn't permitted, as the vma generally has been destroyed by that | |
13 | time. The kfree()ing of vma->vm_private_data must be done in the | |
14 | vm_operations.close actor, and the call to zap_page_range() seems | |
15 | redundant with the caller of that actor altogether. | |
16 | ||
17 | Signed-off-by: Jan Beulich <jbeulich@novell.com> | |
18 | ||
19 | --- sle11-2009-04-20.orig/drivers/xen/blktap/blktap.c 2009-04-20 11:35:28.000000000 +0200 | |
20 | +++ sle11-2009-04-20/drivers/xen/blktap/blktap.c 2009-04-20 11:35:40.000000000 +0200 | |
21 | @@ -293,6 +293,10 @@ static inline int OFFSET_TO_SEG(int offs | |
22 | /****************************************************************** | |
23 | * BLKTAP VM OPS | |
24 | */ | |
25 | +struct tap_vma_priv { | |
26 | + tap_blkif_t *info; | |
27 | + struct page *map[]; | |
28 | +}; | |
29 | ||
30 | static struct page *blktap_nopage(struct vm_area_struct *vma, | |
31 | unsigned long address, | |
32 | @@ -315,7 +319,7 @@ static pte_t blktap_clear_pte(struct vm_ | |
33 | int offset, seg, usr_idx, pending_idx, mmap_idx; | |
34 | unsigned long uvstart = vma->vm_start + (RING_PAGES << PAGE_SHIFT); | |
35 | unsigned long kvaddr; | |
36 | - struct page **map; | |
37 | + struct tap_vma_priv *priv; | |
38 | struct page *pg; | |
39 | struct grant_handle_pair *khandle; | |
40 | struct gnttab_unmap_grant_ref unmap[2]; | |
41 | @@ -330,12 +334,12 @@ static pte_t blktap_clear_pte(struct vm_ | |
42 | ptep, is_fullmm); | |
43 | ||
44 | info = vma->vm_file->private_data; | |
45 | - map = vma->vm_private_data; | |
46 | + priv = vma->vm_private_data; | |
47 | ||
48 | /* TODO Should these be changed to if statements? */ | |
49 | BUG_ON(!info); | |
50 | BUG_ON(!info->idx_map); | |
51 | - BUG_ON(!map); | |
52 | + BUG_ON(!priv); | |
53 | ||
54 | offset = (int) ((uvaddr - uvstart) >> PAGE_SHIFT); | |
55 | usr_idx = OFFSET_TO_USR_IDX(offset); | |
56 | @@ -347,7 +351,7 @@ static pte_t blktap_clear_pte(struct vm_ | |
57 | kvaddr = idx_to_kaddr(mmap_idx, pending_idx, seg); | |
58 | pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); | |
59 | ClearPageReserved(pg); | |
60 | - map[offset + RING_PAGES] = NULL; | |
61 | + priv->map[offset + RING_PAGES] = NULL; | |
62 | ||
63 | khandle = &pending_handle(mmap_idx, pending_idx, seg); | |
64 | ||
65 | @@ -388,9 +392,20 @@ static pte_t blktap_clear_pte(struct vm_ | |
66 | return copy; | |
67 | } | |
68 | ||
69 | +static void blktap_vma_close(struct vm_area_struct *vma) | |
70 | +{ | |
71 | + struct tap_vma_priv *priv = vma->vm_private_data; | |
72 | + | |
73 | + if (priv) { | |
74 | + priv->info->vma = NULL; | |
75 | + kfree(priv); | |
76 | + } | |
77 | +} | |
78 | + | |
79 | struct vm_operations_struct blktap_vm_ops = { | |
80 | nopage: blktap_nopage, | |
81 | zap_pte: blktap_clear_pte, | |
82 | + close: blktap_vma_close, | |
83 | }; | |
84 | ||
85 | /****************************************************************** | |
86 | @@ -609,21 +624,6 @@ static int blktap_release(struct inode * | |
87 | ClearPageReserved(virt_to_page(info->ufe_ring.sring)); | |
88 | free_page((unsigned long) info->ufe_ring.sring); | |
89 | ||
90 | - /* Clear any active mappings and free foreign map table */ | |
91 | - if (info->vma) { | |
92 | - struct mm_struct *mm = info->vma->vm_mm; | |
93 | - | |
94 | - down_write(&mm->mmap_sem); | |
95 | - zap_page_range( | |
96 | - info->vma, info->vma->vm_start, | |
97 | - info->vma->vm_end - info->vma->vm_start, NULL); | |
98 | - up_write(&mm->mmap_sem); | |
99 | - | |
100 | - kfree(info->vma->vm_private_data); | |
101 | - | |
102 | - info->vma = NULL; | |
103 | - } | |
104 | - | |
105 | if (info->idx_map) { | |
106 | kfree(info->idx_map); | |
107 | info->idx_map = NULL; | |
108 | @@ -662,8 +662,7 @@ static int blktap_release(struct inode * | |
109 | static int blktap_mmap(struct file *filp, struct vm_area_struct *vma) | |
110 | { | |
111 | int size; | |
112 | - struct page **map; | |
113 | - int i; | |
114 | + struct tap_vma_priv *priv; | |
115 | tap_blkif_t *info = filp->private_data; | |
116 | int ret; | |
117 | ||
118 | @@ -700,18 +699,16 @@ static int blktap_mmap(struct file *filp | |
119 | } | |
120 | ||
121 | /* Mark this VM as containing foreign pages, and set up mappings. */ | |
122 | - map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) | |
123 | - * sizeof(struct page *), | |
124 | - GFP_KERNEL); | |
125 | - if (map == NULL) { | |
126 | + priv = kzalloc(sizeof(*priv) + ((vma->vm_end - vma->vm_start) | |
127 | + >> PAGE_SHIFT) * sizeof(*priv->map), | |
128 | + GFP_KERNEL); | |
129 | + if (priv == NULL) { | |
130 | WPRINTK("Couldn't alloc VM_FOREIGN map.\n"); | |
131 | goto fail; | |
132 | } | |
133 | + priv->info = info; | |
134 | ||
135 | - for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++) | |
136 | - map[i] = NULL; | |
137 | - | |
138 | - vma->vm_private_data = map; | |
139 | + vma->vm_private_data = priv; | |
140 | vma->vm_flags |= VM_FOREIGN; | |
141 | vma->vm_flags |= VM_DONTCOPY; | |
142 | ||
143 | @@ -1190,7 +1187,7 @@ static int blktap_read_ufe_ring(tap_blki | |
144 | for (j = 0; j < pending_req->nr_pages; j++) { | |
145 | ||
146 | unsigned long kvaddr, uvaddr; | |
147 | - struct page **map = info->vma->vm_private_data; | |
148 | + struct tap_vma_priv *priv = info->vma->vm_private_data; | |
149 | struct page *pg; | |
150 | int offset; | |
151 | ||
152 | @@ -1201,7 +1198,7 @@ static int blktap_read_ufe_ring(tap_blki | |
153 | ClearPageReserved(pg); | |
154 | offset = (uvaddr - info->vma->vm_start) | |
155 | >> PAGE_SHIFT; | |
156 | - map[offset] = NULL; | |
157 | + priv->map[offset] = NULL; | |
158 | } | |
159 | fast_flush_area(pending_req, pending_idx, usr_idx, info->minor); | |
160 | info->idx_map[usr_idx] = INVALID_REQ; | |
161 | @@ -1359,6 +1356,7 @@ static void dispatch_rw_block_io(blkif_t | |
162 | unsigned int nseg; | |
163 | int ret, i, nr_sects = 0; | |
164 | tap_blkif_t *info; | |
165 | + struct tap_vma_priv *priv; | |
166 | blkif_request_t *target; | |
167 | int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx); | |
168 | int usr_idx; | |
169 | @@ -1407,6 +1405,7 @@ static void dispatch_rw_block_io(blkif_t | |
170 | pending_req->status = BLKIF_RSP_OKAY; | |
171 | pending_req->nr_pages = nseg; | |
172 | op = 0; | |
173 | + priv = info->vma->vm_private_data; | |
174 | mm = info->vma->vm_mm; | |
175 | if (!xen_feature(XENFEAT_auto_translated_physmap)) | |
176 | down_write(&mm->mmap_sem); | |
177 | @@ -1490,8 +1489,7 @@ static void dispatch_rw_block_io(blkif_t | |
178 | >> PAGE_SHIFT)); | |
179 | offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; | |
180 | pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); | |
181 | - ((struct page **)info->vma->vm_private_data)[offset] = | |
182 | - pg; | |
183 | + priv->map[offset] = pg; | |
184 | } | |
185 | } else { | |
186 | for (i = 0; i < nseg; i++) { | |
187 | @@ -1518,8 +1516,7 @@ static void dispatch_rw_block_io(blkif_t | |
188 | ||
189 | offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; | |
190 | pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); | |
191 | - ((struct page **)info->vma->vm_private_data)[offset] = | |
192 | - pg; | |
193 | + priv->map[offset] = pg; | |
194 | } | |
195 | } | |
196 |