lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240607024125.jsumfrbgoz5vz3si@treble>
Date: Thu, 6 Jun 2024 19:41:25 -0700
From: Josh Poimboeuf <jpoimboe@...nel.org>
To: Linus Torvalds <torvalds@...ux-foundation.org>
Cc: Peter Zijlstra <peterz@...radead.org>,
	Linux Kernel Mailing List <linux-kernel@...r.kernel.org>
Subject: Re: objtool query: section start/end symbols?

On Thu, Jun 06, 2024 at 03:54:34PM -0700, Linus Torvalds wrote:
> On Thu, 6 Jun 2024 at 15:19, Josh Poimboeuf <jpoimboe@...nel.org> wrote:
> > So while I'm not yet necessarily conceding that objtool is really needed
> > here, I could work up a quick objtool patch.  It would just be x86-only,
> > is that ok for the time being?
> 
> Absolutely.

This adds a new objtool "--bounds" action which creates a

  __sec_<secname>_{start,end}

symbol for every section.

The only testing I've done has been staring cross-eyed at the readelf
output on a defconfig kernel.

If you have CONFIG_X86_KERNEL_IBT -- which causes objtool to run on
vmlinux.o -- you can enable bounds symbol creation by adding
OBJTOOL_ARGS="--bounds" to your make cmdline:

  make -j$(nproc) -s OBJTOOL_ARGS="--bounds"

Otherwise it would need to be manually added with

  objtool --bounds --link vmlinux.o

diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 5e21cfb7661d..e1a86981fd96 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -68,6 +68,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)
 static const struct option check_options[] = {
 	OPT_GROUP("Actions:"),
 	OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks),
+	OPT_BOOLEAN('b', "bounds", &opts.bounds, "generate section start/end bounds symbols"),
 	OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
 	OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
 	OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
@@ -131,7 +132,8 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
 
 static bool opts_valid(void)
 {
-	if (opts.hack_jump_label	||
+	if (opts.bounds			||
+	    opts.hack_jump_label	||
 	    opts.hack_noinstr		||
 	    opts.ibt			||
 	    opts.mcount			||
@@ -199,6 +201,11 @@ static bool link_opts_valid(struct objtool_file *file)
 		return false;
 	}
 
+	if (opts.bounds) {
+		ERROR("--bounds requires --link");
+		return false;
+	}
+
 	return true;
 }
 
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 0a33d9195b7a..59e6638db83f 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4213,6 +4213,124 @@ static int add_prefix_symbols(struct objtool_file *file)
 	return 0;
 }
 
+static bool is_discarded_sec(struct section *sec)
+{
+	static const char * const discards[] = {
+		".note.gnu.property",
+		".export_symbol",
+		".modinfo",
+		"__patchable_function_entries",
+		".exitcall.exit", // not discarded for modules
+	};
+
+	if (!(sec->sh.sh_flags & SHF_ALLOC) || strstarts(sec->name, ".discard"))
+		return true;
+
+	for (int i = 0; i < ARRAY_SIZE(discards); i++)
+		if (!strcmp(sec->name, discards[i]))
+			return true;
+
+	return false;
+}
+
+#define BOUNDS_SEC_NAME ".rodata.sec_bounds"
+
+static int create_bounds_section(struct objtool_file *file)
+{
+	struct section *bounds_sec, *sec;
+	unsigned int idx;
+
+	sec = find_section_by_name(file->elf, BOUNDS_SEC_NAME);
+	if (sec) {
+		INIT_LIST_HEAD(&file->static_call_list);
+		WARN("file already has .sec_bounds section, skipping");
+		return 0;
+	}
+
+	idx = 0;
+	for_each_sec(file, sec)
+		if (sec->idx && !is_reloc_sec(sec) && !is_discarded_sec(sec))
+			idx++;
+
+	bounds_sec = elf_create_section_pair(file->elf, BOUNDS_SEC_NAME,
+					     sizeof(long) * 2, idx, idx * 2);
+	if (!sec)
+		return -1;
+
+	idx = 0;
+	for_each_sec(file, sec) {
+		if (sec->idx && !is_reloc_sec(sec) && !is_discarded_sec(sec)) {
+
+			char sanitized_name[116];
+			char start_name[128];
+			char end_name[128];
+
+			if (!strcmp(sec->name, BOUNDS_SEC_NAME))
+				continue;
+
+			if (!sec->sym && !elf_create_section_symbol(file->elf, sec))
+				return -1;
+
+			strncpy(sanitized_name, sec->name, sizeof(sanitized_name) - 1);
+			for (char *s = sanitized_name; *s; s++)
+				if (*s == '.')
+					*s = '_';
+
+			snprintf(start_name, 256, "__sec%s_start", sanitized_name);
+			snprintf(end_name,   256, "__sec%s_end",   sanitized_name);
+
+			if (find_symbol_by_name(file->elf, start_name) ||
+			    find_symbol_by_name(file->elf, end_name))
+				continue;
+
+			/* 'start' symbol */
+			if (!elf_create_symbol(file->elf,
+					       start_name,
+					       bounds_sec,
+					       STB_GLOBAL,
+					       STT_OBJECT,
+					       idx * 2 * sizeof(long),
+					       sizeof(long)))
+			    return -1;
+
+			if (!elf_create_symbol(file->elf,
+					       end_name,
+					       bounds_sec,
+					       STB_GLOBAL,
+					       STT_OBJECT,
+					       (idx * 2 * sizeof(long)) + sizeof(long),
+					       sizeof(long)))
+			    return -1;
+
+			/* 'start' reloc */
+			if (!elf_init_reloc(file->elf,
+					    bounds_sec->rsec,
+					    idx * 2,
+					    idx * 2 * sizeof(long),
+					    sec->sym,
+					    0,
+					    R_ABS64))
+				return -1;
+
+			/* 'end' reloc */
+			if (!elf_init_reloc(file->elf,
+					    bounds_sec->rsec,
+					    (idx * 2) + 1,
+					    (idx * 2 * sizeof(long)) + sizeof(long),
+					    sec->sym,
+					    sec->sh.sh_size,
+					    R_ABS64))
+				return -1;
+
+
+			idx++;
+		}
+	}
+
+
+	return 0;
+}
+
 static int validate_symbol(struct objtool_file *file, struct section *sec,
 			   struct symbol *sym, struct insn_state *state)
 {
@@ -4826,6 +4944,13 @@ int check(struct objtool_file *file)
 		warnings += ret;
 	}
 
+	if (opts.bounds) {
+		ret = create_bounds_section(file);
+		if (ret < 0)
+			goto out;
+		warnings += ret;
+	}
+
 	if (opts.ibt) {
 		ret = create_ibt_endbr_seal_sections(file);
 		if (ret < 0)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 3d27983dc908..b596e992ca80 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -788,8 +788,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
 	return sym;
 }
 
-static struct symbol *
-elf_create_section_symbol(struct elf *elf, struct section *sec)
+struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec)
 {
 	struct symbol *sym = calloc(1, sizeof(*sym));
 
@@ -811,6 +810,8 @@ elf_create_section_symbol(struct elf *elf, struct section *sec)
 	if (sym)
 		elf_add_symbol(elf, sym);
 
+	sec->sym = sym;
+
 	return sym;
 }
 
@@ -845,10 +846,37 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
 	return sym;
 }
 
-static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
-				    unsigned int reloc_idx,
-				    unsigned long offset, struct symbol *sym,
-				    s64 addend, unsigned int type)
+struct symbol *elf_create_symbol(struct elf *elf, char *name,
+				 struct section *sec, unsigned int bind,
+				 unsigned int type, unsigned long offset,
+				 size_t size)
+{
+	struct symbol *sym = calloc(1, sizeof(*sym));
+
+	if (!sym) {
+		perror("calloc");
+		return NULL;
+	}
+
+	sym->name = strdup(name);
+	sym->sec = sec;
+
+	sym->sym.st_name = elf_add_string(elf, NULL, sym->name);
+	sym->sym.st_info = GELF_ST_INFO(bind, type);
+	sym->sym.st_value = offset;
+	sym->sym.st_size = size;
+
+	sym = __elf_create_symbol(elf, sym);
+	if (sym)
+		elf_add_symbol(elf, sym);
+
+	return sym;
+}
+
+struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
+			     unsigned int reloc_idx,
+			     unsigned long offset, struct symbol *sym,
+			     s64 addend, unsigned int type)
 {
 	struct reloc *reloc, empty = { 0 };
 
@@ -906,8 +934,6 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
 		sym = elf_create_section_symbol(elf, insn_sec);
 		if (!sym)
 			return NULL;
-
-		insn_sec->sym = sym;
 	}
 
 	return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index fcca6662c8b4..c0a73e247722 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -30,6 +30,7 @@ struct opts {
 	/* options: */
 	bool backtrace;
 	bool backup;
+	bool bounds;
 	bool dryrun;
 	bool link;
 	bool mnop;
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 2b8a69de4db8..a2f9c1b4ca88 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -113,8 +113,20 @@ struct section *elf_create_section_pair(struct elf *elf, const char *name,
 					size_t entsize, unsigned int nr,
 					unsigned int reloc_nr);
 
+struct symbol *elf_create_symbol(struct elf *elf, char *name,
+				 struct section *sec, unsigned int bind,
+				 unsigned int type, unsigned long offset,
+				 size_t size);
+
+struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec);
+
 struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
 
+struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
+			     unsigned int reloc_idx,
+			     unsigned long offset, struct symbol *sym,
+			     s64 addend, unsigned int type);
+
 struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
 				      unsigned long offset,
 				      unsigned int reloc_idx,

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ