hc
2024-05-10 748e4f3d702def1a4bff191e0cf93b6a05340f01
kernel/arch/sparc/vdso/vma.c
....@@ -1,7 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Set up the VMAs to tell the VM about the vDSO.
34 * Copyright 2007 Andi Kleen, SUSE Labs.
4
- * Subject to the GPL, v.2
55 */
66
77 /*
....@@ -16,6 +16,8 @@
1616 #include <linux/linkage.h>
1717 #include <linux/random.h>
1818 #include <linux/elf.h>
19
+#include <asm/cacheflush.h>
20
+#include <asm/spitfire.h>
1921 #include <asm/vdso.h>
2022 #include <asm/vvar.h>
2123 #include <asm/page.h>
....@@ -40,20 +42,221 @@
4042
4143 struct vvar_data *vvar_data;
4244
43
-#define SAVE_INSTR_SIZE 4
45
+struct vdso_elfinfo32 {
46
+ Elf32_Ehdr *hdr;
47
+ Elf32_Sym *dynsym;
48
+ unsigned long dynsymsize;
49
+ const char *dynstr;
50
+ unsigned long text;
51
+};
52
+
53
+struct vdso_elfinfo64 {
54
+ Elf64_Ehdr *hdr;
55
+ Elf64_Sym *dynsym;
56
+ unsigned long dynsymsize;
57
+ const char *dynstr;
58
+ unsigned long text;
59
+};
60
+
61
+struct vdso_elfinfo {
62
+ union {
63
+ struct vdso_elfinfo32 elf32;
64
+ struct vdso_elfinfo64 elf64;
65
+ } u;
66
+};
67
+
68
+static void *one_section64(struct vdso_elfinfo64 *e, const char *name,
69
+ unsigned long *size)
70
+{
71
+ const char *snames;
72
+ Elf64_Shdr *shdrs;
73
+ unsigned int i;
74
+
75
+ shdrs = (void *)e->hdr + e->hdr->e_shoff;
76
+ snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset;
77
+ for (i = 1; i < e->hdr->e_shnum; i++) {
78
+ if (!strcmp(snames+shdrs[i].sh_name, name)) {
79
+ if (size)
80
+ *size = shdrs[i].sh_size;
81
+ return (void *)e->hdr + shdrs[i].sh_offset;
82
+ }
83
+ }
84
+ return NULL;
85
+}
86
+
87
+static int find_sections64(const struct vdso_image *image, struct vdso_elfinfo *_e)
88
+{
89
+ struct vdso_elfinfo64 *e = &_e->u.elf64;
90
+
91
+ e->hdr = image->data;
92
+ e->dynsym = one_section64(e, ".dynsym", &e->dynsymsize);
93
+ e->dynstr = one_section64(e, ".dynstr", NULL);
94
+
95
+ if (!e->dynsym || !e->dynstr) {
96
+ pr_err("VDSO64: Missing symbol sections.\n");
97
+ return -ENODEV;
98
+ }
99
+ return 0;
100
+}
101
+
102
+static Elf64_Sym *find_sym64(const struct vdso_elfinfo64 *e, const char *name)
103
+{
104
+ unsigned int i;
105
+
106
+ for (i = 0; i < (e->dynsymsize / sizeof(Elf64_Sym)); i++) {
107
+ Elf64_Sym *s = &e->dynsym[i];
108
+ if (s->st_name == 0)
109
+ continue;
110
+ if (!strcmp(e->dynstr + s->st_name, name))
111
+ return s;
112
+ }
113
+ return NULL;
114
+}
115
+
116
+static int patchsym64(struct vdso_elfinfo *_e, const char *orig,
117
+ const char *new)
118
+{
119
+ struct vdso_elfinfo64 *e = &_e->u.elf64;
120
+ Elf64_Sym *osym = find_sym64(e, orig);
121
+ Elf64_Sym *nsym = find_sym64(e, new);
122
+
123
+ if (!nsym || !osym) {
124
+ pr_err("VDSO64: Missing symbols.\n");
125
+ return -ENODEV;
126
+ }
127
+ osym->st_value = nsym->st_value;
128
+ osym->st_size = nsym->st_size;
129
+ osym->st_info = nsym->st_info;
130
+ osym->st_other = nsym->st_other;
131
+ osym->st_shndx = nsym->st_shndx;
132
+
133
+ return 0;
134
+}
135
+
136
+static void *one_section32(struct vdso_elfinfo32 *e, const char *name,
137
+ unsigned long *size)
138
+{
139
+ const char *snames;
140
+ Elf32_Shdr *shdrs;
141
+ unsigned int i;
142
+
143
+ shdrs = (void *)e->hdr + e->hdr->e_shoff;
144
+ snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset;
145
+ for (i = 1; i < e->hdr->e_shnum; i++) {
146
+ if (!strcmp(snames+shdrs[i].sh_name, name)) {
147
+ if (size)
148
+ *size = shdrs[i].sh_size;
149
+ return (void *)e->hdr + shdrs[i].sh_offset;
150
+ }
151
+ }
152
+ return NULL;
153
+}
154
+
155
+static int find_sections32(const struct vdso_image *image, struct vdso_elfinfo *_e)
156
+{
157
+ struct vdso_elfinfo32 *e = &_e->u.elf32;
158
+
159
+ e->hdr = image->data;
160
+ e->dynsym = one_section32(e, ".dynsym", &e->dynsymsize);
161
+ e->dynstr = one_section32(e, ".dynstr", NULL);
162
+
163
+ if (!e->dynsym || !e->dynstr) {
164
+ pr_err("VDSO32: Missing symbol sections.\n");
165
+ return -ENODEV;
166
+ }
167
+ return 0;
168
+}
169
+
170
+static Elf32_Sym *find_sym32(const struct vdso_elfinfo32 *e, const char *name)
171
+{
172
+ unsigned int i;
173
+
174
+ for (i = 0; i < (e->dynsymsize / sizeof(Elf32_Sym)); i++) {
175
+ Elf32_Sym *s = &e->dynsym[i];
176
+ if (s->st_name == 0)
177
+ continue;
178
+ if (!strcmp(e->dynstr + s->st_name, name))
179
+ return s;
180
+ }
181
+ return NULL;
182
+}
183
+
184
+static int patchsym32(struct vdso_elfinfo *_e, const char *orig,
185
+ const char *new)
186
+{
187
+ struct vdso_elfinfo32 *e = &_e->u.elf32;
188
+ Elf32_Sym *osym = find_sym32(e, orig);
189
+ Elf32_Sym *nsym = find_sym32(e, new);
190
+
191
+ if (!nsym || !osym) {
192
+ pr_err("VDSO32: Missing symbols.\n");
193
+ return -ENODEV;
194
+ }
195
+ osym->st_value = nsym->st_value;
196
+ osym->st_size = nsym->st_size;
197
+ osym->st_info = nsym->st_info;
198
+ osym->st_other = nsym->st_other;
199
+ osym->st_shndx = nsym->st_shndx;
200
+
201
+ return 0;
202
+}
203
+
204
+static int find_sections(const struct vdso_image *image, struct vdso_elfinfo *e,
205
+ bool elf64)
206
+{
207
+ if (elf64)
208
+ return find_sections64(image, e);
209
+ else
210
+ return find_sections32(image, e);
211
+}
212
+
213
+static int patch_one_symbol(struct vdso_elfinfo *e, const char *orig,
214
+ const char *new_target, bool elf64)
215
+{
216
+ if (elf64)
217
+ return patchsym64(e, orig, new_target);
218
+ else
219
+ return patchsym32(e, orig, new_target);
220
+}
221
+
222
+static int stick_patch(const struct vdso_image *image, struct vdso_elfinfo *e, bool elf64)
223
+{
224
+ int err;
225
+
226
+ err = find_sections(image, e, elf64);
227
+ if (err)
228
+ return err;
229
+
230
+ err = patch_one_symbol(e,
231
+ "__vdso_gettimeofday",
232
+ "__vdso_gettimeofday_stick", elf64);
233
+ if (err)
234
+ return err;
235
+
236
+ return patch_one_symbol(e,
237
+ "__vdso_clock_gettime",
238
+ "__vdso_clock_gettime_stick", elf64);
239
+ return 0;
240
+}
44241
45242 /*
46243 * Allocate pages for the vdso and vvar, and copy in the vdso text from the
47244 * kernel image.
48245 */
49246 int __init init_vdso_image(const struct vdso_image *image,
50
- struct vm_special_mapping *vdso_mapping)
247
+ struct vm_special_mapping *vdso_mapping, bool elf64)
51248 {
52
- int i;
53
- struct page *dp, **dpp = NULL;
54
- int dnpages = 0;
55
- struct page *cp, **cpp = NULL;
56249 int cnpages = (image->size) / PAGE_SIZE;
250
+ struct page *dp, **dpp = NULL;
251
+ struct page *cp, **cpp = NULL;
252
+ struct vdso_elfinfo ei;
253
+ int i, dnpages = 0;
254
+
255
+ if (tlb_type != spitfire) {
256
+ int err = stick_patch(image, &ei, elf64);
257
+ if (err)
258
+ return err;
259
+ }
57260
58261 /*
59262 * First, the vdso text. This is initialied data, an integral number of
....@@ -67,22 +270,6 @@
67270
68271 if (!cpp)
69272 goto oom;
70
-
71
- if (vdso_fix_stick) {
72
- /*
73
- * If the system uses %tick instead of %stick, patch the VDSO
74
- * with instruction reading %tick instead of %stick.
75
- */
76
- unsigned int j, k = SAVE_INSTR_SIZE;
77
- unsigned char *data = image->data;
78
-
79
- for (j = image->sym_vread_tick_patch_start;
80
- j < image->sym_vread_tick_patch_end; j++) {
81
-
82
- data[image->sym_vread_tick + k] = data[j];
83
- k++;
84
- }
85
- }
86273
87274 for (i = 0; i < cnpages; i++) {
88275 cp = alloc_page(GFP_KERNEL);
....@@ -146,13 +333,13 @@
146333 {
147334 int err = 0;
148335 #ifdef CONFIG_SPARC64
149
- err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64);
336
+ err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64, true);
150337 if (err)
151338 return err;
152339 #endif
153340
154341 #ifdef CONFIG_COMPAT
155
- err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32);
342
+ err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32, false);
156343 #endif
157344 return err;
158345
....@@ -179,7 +366,7 @@
179366 unsigned long text_start, addr = 0;
180367 int ret = 0;
181368
182
- down_write(&mm->mmap_sem);
369
+ mmap_write_lock(mm);
183370
184371 /*
185372 * First, get an unmapped region: then randomize it, and make sure that
....@@ -235,7 +422,7 @@
235422 if (ret)
236423 current->mm->context.vdso = NULL;
237424
238
- up_write(&mm->mmap_sem);
425
+ mmap_write_unlock(mm);
239426 return ret;
240427 }
241428