History

livepatch: add old_sympos as disambiguator field to klp_func

Currently, patching objects with duplicate symbol names fail because the creation of the sysfs function directory collides with the previous attempt. Appending old_addr to the function name is problematic as it reveals the address of the function being patch to a normal user. Using the symbol's occurrence in kallsyms to postfix the function name in the sysfs directory solves the issue of having consistent unique names and ensuring that the address is not exposed to a normal user. In addition, using the symbol position as the user's method to disambiguate symbols instead of addr allows for disambiguating symbols in modules as well for both function addresses and for relocs. This also simplifies much of the code. Special handling for kASLR is no longer needed and can be removed. The klp_find_verify_func_addr function can be replaced by klp_find_object_symbol, and klp_verify_vmlinux_symbol and its callback can be removed completely. In cases of duplicate symbols, old_sympos will be used to disambiguate instead of old_addr. By default old_sympos will be 0, and patching will only succeed if the symbol is unique. Specifying a positive value will ensure that occurrence of the symbol in kallsyms for the patched object will be used for patching if it is valid. In addition, make old_addr an internal structure field not to be specified by the user. Finally, remove klp_find_verify_func_addr as it can be replaced by klp_find_object_symbol directly. Support for symbol position disambiguation for relocations is added in the next patch in this series.

Chris J Arges committed 10 years ago

Commit b2b018e1 parent a3d66b52 files · +41 −50Browse files

Showing the changes to kernel/livepatch (1 of 2 files). Show all

Unified · Split

kernel/livepatch/core.c+31−41
@@ -135,13 +135,8 @@ struct klp_find_arg { · 134 unmodified lines
135135 const char *objname;
136136 const char *name;
137137 unsigned long addr;
138− /*
139− * If count == 0, the symbol was not found. If count == 1, a unique
140− * match was found and addr is set. If count > 1, there is
141− * unresolvable ambiguity among "count" number of symbols with the same
142− * name in the same object.
143− */
144138 unsigned long count;
139+ unsigned long pos;
145140 };
146141
147142 static int klp_find_callback(void *data, const char *name,
@@ -158,37 +153,48 @@ static int klp_find_callback(void *data, const char *name, · 10 unmodified lines
158153 if (args->objname && strcmp(args->objname, mod->name))
159154 return 0;
160155
161− /*
162− * args->addr might be overwritten if another match is found
163− * but klp_find_object_symbol() handles this and only returns the
164− * addr if count == 1.
165− */
166156 args->addr = addr;
167157 args->count++;
168158
159+ /*
160+ * Finish the search when the symbol is found for the desired position
161+ * or the position is not defined for a non-unique symbol.
162+ */
163+ if ((args->pos && (args->count == args->pos)) ||
164+ (!args->pos && (args->count > 1)))
165+ return 1;
166+
169167 return 0;
170168 }
171169
172170 static int klp_find_object_symbol(const char *objname, const char *name,
173− unsigned long *addr)
171+ unsigned long sympos, unsigned long *addr)
174172 {
175173 struct klp_find_arg args = {
176174 .objname = objname,
177175 .name = name,
178176 .addr = 0,
179− .count = 0
177+ .count = 0,
178+ .pos = sympos,
180179 };
181180
182181 mutex_lock(&module_mutex);
183182 kallsyms_on_each_symbol(klp_find_callback, &args);
184183 mutex_unlock(&module_mutex);
185184
186− if (args.count == 0)
185+ /*
186+ * Ensure an address was found. If sympos is 0, ensure symbol is unique;
187+ * otherwise ensure the symbol position count matches sympos.
188+ */
189+ if (args.addr == 0)
187190 pr_err("symbol '%s' not found in symbol table\n", name);
188− else if (args.count > 1)
191+ else if (args.count > 1 && sympos == 0) {
189192 pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n",
190193 args.count, name, objname);
191− else {
194+ } else if (sympos != args.count && sympos > 0) {
195+ pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n",
196+ sympos, name, objname ? objname : "vmlinux");
197+ } else {
192198 *addr = args.addr;
193199 return 0;
194200 }
@@ -236,27 +242,6 @@ static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr) · 41 unmodified lines
236242 return 0;
237243 }
238244
239−static int klp_find_verify_func_addr(struct klp_object *obj,
240− struct klp_func *func)
241−{
242− int ret;
243−
244−#if defined(CONFIG_RANDOMIZE_BASE)
245− /* If KASLR has been enabled, adjust old_addr accordingly */
246− if (kaslr_enabled() && func->old_addr)
247− func->old_addr += kaslr_offset();
248−#endif
249−
250− if (!func->old_addr || klp_is_module(obj))
251− ret = klp_find_object_symbol(obj->name, func->old_name,
252− &func->old_addr);
253− else
254− ret = klp_verify_vmlinux_symbol(func->old_name,
255− func->old_addr);
256−
257− return ret;
258−}
259−
260245 /*
261246 * external symbols are located outside the parent object (where the parent
262247 * object is either vmlinux or the kmod being patched).
@@ -276,8 +261,11 @@ static int klp_find_external_symbol(struct module *pmod, const char *name, · 13 unmodified lines
276261 }
277262 preempt_enable();
278263
279− /* otherwise check if it's in another .o within the patch module */
280− return klp_find_object_symbol(pmod->name, name, addr);
264+ /*
265+ * Check if it's in another .o within the patch module. This also
266+ * checks that the external symbol is unique.
267+ */
268+ return klp_find_object_symbol(pmod->name, name, 0, addr);
281269 }
282270
283271 static int klp_write_object_relocations(struct module *pmod,
@@ -313,7 +301,7 @@ static int klp_write_object_relocations(struct module *pmod, · 29 unmodified lines
313301 else
314302 ret = klp_find_object_symbol(obj->mod->name,
315303 reloc->name,
316− &reloc->val);
304+ 0, &reloc->val);
317305 if (ret)
318306 return ret;
319307 }
@@ -756,7 +744,9 @@ static int klp_init_object_loaded(struct klp_patch *patch, · 436 unmodified lines
756744 }
757745
758746 klp_for_each_func(obj, func) {
759− ret = klp_find_verify_func_addr(obj, func);
747+ ret = klp_find_object_symbol(obj->name, func->old_name,
748+ func->old_sympos,
749+ &func->old_addr);
760750 if (ret)
761751 return ret;
762752 }