Tue Jan 7 11:54:58 2020 UTC ()
Pull up following revision(s) (requested by pgoyette in ticket #609):

	sys/kern/kern_ksyms.c: revision 1.88

When reading from /dev/ksyms we need to skip over entries that have
been marked as sd_gone.  Otherwise we might try to uiomove() data from
memory that has been unmapped, resulting in EFAULT.

XXX This (along with other pre-existing checks st->sd_gone) is still
racy, but it's an improvement over current code.  Ideally we would
make a complete copy of the symbol table when we open /dev/ksyms so
we could ignore any changes that occur.

ad@ says "good enough for now"

XXX Pullup to -9 and -8


(martin)
diff -r1.87 -r1.87.8.1 src/sys/kern/kern_ksyms.c

cvs diff -r1.87 -r1.87.8.1 src/sys/kern/kern_ksyms.c (expand / switch to unified diff)

--- src/sys/kern/kern_ksyms.c 2017/11/04 22:17:55 1.87
+++ src/sys/kern/kern_ksyms.c 2020/01/07 11:54:57 1.87.8.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: kern_ksyms.c,v 1.87 2017/11/04 22:17:55 christos Exp $ */ 1/* $NetBSD: kern_ksyms.c,v 1.87.8.1 2020/01/07 11:54:57 martin Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software developed for The NetBSD Foundation 7 * This code is derived from software developed for The NetBSD Foundation
8 * by Andrew Doran. 8 * by Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -63,27 +63,27 @@ @@ -63,27 +63,27 @@
63 * struct, placed in a circular list. The first entry is the kernel 63 * struct, placed in a circular list. The first entry is the kernel
64 * symbol table. 64 * symbol table.
65 */ 65 */
66 66
67/* 67/*
68 * TODO: 68 * TODO:
69 * 69 *
70 * Add support for mmap, poll. 70 * Add support for mmap, poll.
71 * Constify tables. 71 * Constify tables.
72 * Constify db_symtab and move it to .rodata. 72 * Constify db_symtab and move it to .rodata.
73 */ 73 */
74 74
75#include <sys/cdefs.h> 75#include <sys/cdefs.h>
76__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.87 2017/11/04 22:17:55 christos Exp $"); 76__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.87.8.1 2020/01/07 11:54:57 martin Exp $");
77 77
78#if defined(_KERNEL) && defined(_KERNEL_OPT) 78#if defined(_KERNEL) && defined(_KERNEL_OPT)
79#include "opt_copy_symtab.h" 79#include "opt_copy_symtab.h"
80#include "opt_ddb.h" 80#include "opt_ddb.h"
81#include "opt_dtrace.h" 81#include "opt_dtrace.h"
82#endif 82#endif
83 83
84#define _KSYMS_PRIVATE 84#define _KSYMS_PRIVATE
85 85
86#include <sys/param.h> 86#include <sys/param.h>
87#include <sys/queue.h> 87#include <sys/queue.h>
88#include <sys/exec.h> 88#include <sys/exec.h>
89#include <sys/systm.h> 89#include <sys/systm.h>
@@ -755,29 +755,29 @@ ksyms_modload(const char *name, void *sy @@ -755,29 +755,29 @@ ksyms_modload(const char *name, void *sy
755 */ 755 */
756void 756void
757ksyms_modunload(const char *name) 757ksyms_modunload(const char *name)
758{ 758{
759 struct ksyms_symtab *st; 759 struct ksyms_symtab *st;
760 760
761 mutex_enter(&ksyms_lock); 761 mutex_enter(&ksyms_lock);
762 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 762 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
763 if (st->sd_gone) 763 if (st->sd_gone)
764 continue; 764 continue;
765 if (strcmp(name, st->sd_name) != 0) 765 if (strcmp(name, st->sd_name) != 0)
766 continue; 766 continue;
767 st->sd_gone = true; 767 st->sd_gone = true;
 768 ksyms_sizes_calc();
768 if (!ksyms_isopen) { 769 if (!ksyms_isopen) {
769 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue); 770 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
770 ksyms_sizes_calc(); 
771 kmem_free(st->sd_nmap, 771 kmem_free(st->sd_nmap,
772 st->sd_nmapsize * sizeof(uint32_t)); 772 st->sd_nmapsize * sizeof(uint32_t));
773 kmem_free(st, sizeof(*st)); 773 kmem_free(st, sizeof(*st));
774 } 774 }
775 break; 775 break;
776 } 776 }
777 mutex_exit(&ksyms_lock); 777 mutex_exit(&ksyms_lock);
778 KASSERT(st != NULL); 778 KASSERT(st != NULL);
779} 779}
780 780
781#ifdef DDB 781#ifdef DDB
782/* 782/*
783 * Keep sifting stuff here, to avoid export of ksyms internals. 783 * Keep sifting stuff here, to avoid export of ksyms internals.
@@ -846,26 +846,28 @@ ksyms_sift(char *mod, char *sym, int mod @@ -846,26 +846,28 @@ ksyms_sift(char *mod, char *sym, int mod
846 * The actual (correct) value of st_name is preserved through a global 846 * The actual (correct) value of st_name is preserved through a global
847 * offset stored in the symbol table structure. 847 * offset stored in the symbol table structure.
848 * 848 *
849 * Call with ksyms_lock held. 849 * Call with ksyms_lock held.
850 */ 850 */
851static void 851static void
852ksyms_sizes_calc(void) 852ksyms_sizes_calc(void)
853{ 853{
854 struct ksyms_symtab *st; 854 struct ksyms_symtab *st;
855 int i, delta; 855 int i, delta;
856 856
857 ksyms_symsz = ksyms_strsz = 0; 857 ksyms_symsz = ksyms_strsz = 0;
858 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 858 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
 859 if (__predict_false(st->sd_gone))
 860 continue;
859 delta = ksyms_strsz - st->sd_usroffset; 861 delta = ksyms_strsz - st->sd_usroffset;
860 if (delta != 0) { 862 if (delta != 0) {
861 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++) 863 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
862 st->sd_symstart[i].st_name += delta; 864 st->sd_symstart[i].st_name += delta;
863 st->sd_usroffset = ksyms_strsz; 865 st->sd_usroffset = ksyms_strsz;
864 } 866 }
865 ksyms_symsz += st->sd_symsize; 867 ksyms_symsz += st->sd_symsize;
866 ksyms_strsz += st->sd_strsize; 868 ksyms_strsz += st->sd_strsize;
867 } 869 }
868} 870}
869 871
870static void 872static void
871ksyms_fill_note(void) 873ksyms_fill_note(void)
@@ -1024,44 +1026,48 @@ ksymsread(dev_t dev, struct uio *uio, in @@ -1024,44 +1026,48 @@ ksymsread(dev_t dev, struct uio *uio, in
1024 off = uio->uio_offset; 1026 off = uio->uio_offset;
1025 if (off < sizeof(struct ksyms_hdr)) { 1027 if (off < sizeof(struct ksyms_hdr)) {
1026 error = uiomove((char *)&ksyms_hdr + off, 1028 error = uiomove((char *)&ksyms_hdr + off,
1027 sizeof(struct ksyms_hdr) - off, uio); 1029 sizeof(struct ksyms_hdr) - off, uio);
1028 if (error != 0) 1030 if (error != 0)
1029 return error; 1031 return error;
1030 } 1032 }
1031 1033
1032 /* 1034 /*
1033 * Copy out the symbol table. 1035 * Copy out the symbol table.
1034 */ 1036 */
1035 filepos = sizeof(struct ksyms_hdr); 1037 filepos = sizeof(struct ksyms_hdr);
1036 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 1038 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
 1039 if (__predict_false(st->sd_gone))
 1040 continue;
1037 if (uio->uio_resid == 0) 1041 if (uio->uio_resid == 0)
1038 return 0; 1042 return 0;
1039 if (uio->uio_offset <= st->sd_symsize + filepos) { 1043 if (uio->uio_offset <= st->sd_symsize + filepos) {
1040 inpos = uio->uio_offset - filepos; 1044 inpos = uio->uio_offset - filepos;
1041 error = uiomove((char *)st->sd_symstart + inpos, 1045 error = uiomove((char *)st->sd_symstart + inpos,
1042 st->sd_symsize - inpos, uio); 1046 st->sd_symsize - inpos, uio);
1043 if (error != 0) 1047 if (error != 0)
1044 return error; 1048 return error;
1045 } 1049 }
1046 filepos += st->sd_symsize; 1050 filepos += st->sd_symsize;
1047 } 1051 }
1048 1052
1049 /* 1053 /*
1050 * Copy out the string table 1054 * Copy out the string table
1051 */ 1055 */
1052 KASSERT(filepos == sizeof(struct ksyms_hdr) + 1056 KASSERT(filepos == sizeof(struct ksyms_hdr) +
1053 ksyms_hdr.kh_shdr[SYMTAB].sh_size); 1057 ksyms_hdr.kh_shdr[SYMTAB].sh_size);
1054 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 1058 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
 1059 if (__predict_false(st->sd_gone))
 1060 continue;
1055 if (uio->uio_resid == 0) 1061 if (uio->uio_resid == 0)
1056 return 0; 1062 return 0;
1057 if (uio->uio_offset <= st->sd_strsize + filepos) { 1063 if (uio->uio_offset <= st->sd_strsize + filepos) {
1058 inpos = uio->uio_offset - filepos; 1064 inpos = uio->uio_offset - filepos;
1059 error = uiomove((char *)st->sd_strstart + inpos, 1065 error = uiomove((char *)st->sd_strstart + inpos,
1060 st->sd_strsize - inpos, uio); 1066 st->sd_strsize - inpos, uio);
1061 if (error != 0) 1067 if (error != 0)
1062 return error; 1068 return error;
1063 } 1069 }
1064 filepos += st->sd_strsize; 1070 filepos += st->sd_strsize;
1065 } 1071 }
1066 1072
1067 /* 1073 /*