shithub: riscv

Download patch

ref: c2297ce5c180e98f2217a691a25d19a300956d9f
parent: d168b89ab110a2d1fcaf72ad085a789092b82b00
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat May 29 10:18:35 EDT 2021

kernel: use 64-bit virtual entry point for expanded header, document behaviour in a.out(6)

For 64-bit architectures, the a.out header has the HDR_MAGIC flag set
in the magic and is expanded by 8 bytes containing the 64-bit virtual
address of the programs entry point. While Exec.entry contains physical
address for kernel images.

Our sysexec() would always use Exec.entry, even for 64-bit a.out binaries,
which worked because PADDR(entry) == entry for userspace pointers.

This change fixes it, having the kernel use the 64-bit entry point
and document the behaviour in the manpage.

--- a/sys/man/6/a.out
+++ b/sys/man/6/a.out
@@ -25,7 +25,7 @@
 	long	pcsz;	/* size of pc/line number table */
 } Exec;
 
-#define HDR_MAGIC	0x00008000
+#define HDR_MAGIC	0x00008000	/* header expansion */
 
 #define	_MAGIC(f, b)	((f)|((((4*(b))+0)*(b))+7))
 #define	A_MAGIC	_MAGIC(0, 8)		/* 68020 */
@@ -62,7 +62,18 @@
 bytes of the binary file.
 The
 .B entry
-field gives the virtual address of the entry point of the program.
+field gives the virtual address of the entry point of the program
+unless
+.B HDR_MAGIC
+flag is present in the
+.B magic
+field.
+In that case, the header is expanded
+by 8 bytes containing the 64-bit virtual address of the
+program entry point and the 32-bit
+.B entry
+field is reserved for physical kernel entry point.
+.PP
 The data segment starts at the first page-rounded virtual address
 after the text segment.
 It consists of the next
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -10,6 +10,8 @@
 int		anyhigher(void);
 int		anyready(void);
 Image*		attachimage(int, Chan*, uintptr, ulong);
+ulong		beswal(ulong);
+uvlong		beswav(uvlong);
 int		blocklen(Block*);
 void		bootlinks(void);
 void		cachedel(Image*, uintptr);
--- a/sys/src/9/port/rebootcmd.c
+++ b/sys/src/9/port/rebootcmd.c
@@ -6,16 +6,6 @@
 #include	"../port/error.h"
 #include	"a.out.h"
 
-static ulong
-l2be(long l)
-{
-	uchar *cp;
-
-	cp = (uchar*)&l;
-	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
-}
-
-
 static void
 readn(Chan *c, void *vp, long n)
 {
@@ -35,8 +25,11 @@
 void
 rebootcmd(int argc, char *argv[])
 {
+	struct {
+		Exec;
+		uvlong	hdr[1];
+	} ehdr;
 	Chan *c;
-	Exec exec;
 	ulong magic, text, rtext, entry, data, size, align;
 	uchar *p;
 
@@ -49,11 +42,11 @@
 		nexterror();
 	}
 
-	readn(c, &exec, sizeof(Exec));
-	magic = l2be(exec.magic);
-	entry = l2be(exec.entry);
-	text = l2be(exec.text);
-	data = l2be(exec.data);
+	readn(c, &ehdr, sizeof(Exec));
+	magic = beswal(ehdr.magic);
+	entry = beswal(ehdr.entry);
+	text = beswal(ehdr.text);
+	data = beswal(ehdr.data);
 
 	if(!(magic == AOUT_MAGIC)){
 		switch(magic){
@@ -66,7 +59,7 @@
 		}
 	}
 	if(magic & HDR_MAGIC)
-		readn(c, &exec, 8);
+		readn(c, ehdr.hdr, sizeof(ehdr.hdr));
 
 	switch(magic){
 	case R_MAGIC:
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -234,6 +234,8 @@
 {
 	int i;
 
+	if(n <= 2 || s[0] != '#' || s[1] != '!')
+		return -1;
 	s += 2;
 	n -= 2;		/* skip #! */
 	for(i=0;; i++){
@@ -261,20 +263,35 @@
 	return i;
 }
 
-static ulong
-l2be(long l)
+ulong
+beswal(ulong l)
 {
-	uchar *cp;
+	uchar *p;
 
-	cp = (uchar*)&l;
-	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
+	p = (uchar*)&l;
+	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
 }
 
+uvlong
+beswav(uvlong v)
+{
+	uchar *p;
+
+	p = (uchar*)&v;
+	return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
+				  | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
+				  | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
+				  | (uvlong)p[7];
+}
+
 uintptr
 sysexec(va_list list)
 {
-	Exec exec;
-	char line[sizeof(Exec)];
+	struct {
+		Exec;
+		uvlong	hdr[1];
+	} ehdr;
+	char line[sizeof(ehdr)];
 	char *progarg[sizeof(line)/2+1];
 	volatile char *args, *elem, *file0;
 	char **argv, **argp, **argp0;
@@ -281,7 +298,7 @@
 	char *a, *e, *charp, *file;
 	int i, n, indir;
 	ulong magic, ssize, nargs, nbytes;
-	uintptr t, d, b, entry, bssend, text, data, bss, tstk, align;
+	uintptr t, d, b, entry, text, data, bss, bssend, tstk, align;
 	Segment *s, *ts;
 	Image *img;
 	Tos *tos;
@@ -311,7 +328,7 @@
 		}
 		nexterror();
 	}
-	align = BY2PG;
+	align = BY2PG-1;
 	indir = 0;
 	file = file0;
 	for(;;){
@@ -323,39 +340,47 @@
 		if(!indir)
 			kstrdup(&elem, up->genbuf);
 
-		n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
-		if(n <= 2)
-			error(Ebadexec);
-		magic = l2be(exec.magic);
-		if(n == sizeof(Exec) && (magic == AOUT_MAGIC)){
-			entry = l2be(exec.entry);
-			text = l2be(exec.text);
-			if(magic & HDR_MAGIC)
-				text += 8;
-			switch(magic){
-			case S_MAGIC:	/* 2MB segment alignment for amd64 */
-				align = 0x200000;
-				break;
-			case V_MAGIC:	/* 16K segment alignment for mips */
-				align = 0x4000;
-				break;
-			case R_MAGIC:	/* 64K segment alignment for arm64 */
-				align = 0x10000;
-				break;
+		n = devtab[tc->type]->read(tc, &ehdr, sizeof(ehdr), 0);
+		if(n >= sizeof(Exec)) {
+			magic = beswal(ehdr.magic);
+			if(magic == AOUT_MAGIC) {
+				if(magic & HDR_MAGIC) {
+					if(n < sizeof(ehdr))
+						error(Ebadexec);
+					entry = beswav(ehdr.hdr[0]);
+					text = UTZERO+sizeof(ehdr);
+				} else {
+					entry = beswal(ehdr.entry);
+					text = UTZERO+sizeof(Exec);
+				}
+				if(entry < text)
+					error(Ebadexec);
+				text += beswal(ehdr.text);
+				if(text <= entry || text >= (USTKTOP-USTKSIZE))
+					error(Ebadexec);
+
+				switch(magic){
+				case S_MAGIC:	/* 2MB segment alignment for amd64 */
+					align = 0x1fffff;
+					break;
+				case V_MAGIC:	/* 16K segment alignment for mips */
+					align = 0x3fff;
+					break;
+				case R_MAGIC:	/* 64K segment alignment for arm64 */
+					align = 0xffff;
+					break;
+				}
+				break; /* for binary */
 			}
-			if(text >= (USTKTOP-USTKSIZE)-(UTZERO+sizeof(Exec))
-			|| entry < UTZERO+sizeof(Exec)
-			|| entry >= UTZERO+sizeof(Exec)+text)
-				error(Ebadexec);
-			break; /* for binary */
 		}
 
+		if(indir++)
+			error(Ebadexec);
+
 		/*
 		 * Process #! /bin/sh args ...
 		 */
-		memmove(line, &exec, n);
-		if(line[0]!='#' || line[1]!='!' || indir++)
-			error(Ebadexec);
+		memmove(line, &ehdr, n);
 		n = shargs(line, n, progarg);
 		if(n < 1)
 			error(Ebadexec);
@@ -371,10 +396,10 @@
 		cclose(tc);
 	}
 
-	data = l2be(exec.data);
-	bss = l2be(exec.bss);
-	align--;
-	t = (UTZERO+sizeof(Exec)+text+align) & ~align;
+	t = (text+align) & ~align;
+	text -= UTZERO;
+	data = beswal(ehdr.data);
+	bss = beswal(ehdr.bss);
 	align = BY2PG-1;
 	d = (t + data + align) & ~align;
 	bssend = t + data + bss;
@@ -518,7 +543,7 @@
 	up->seg[TSEG] = ts;
 	ts->flushme = 1;
 	ts->fstart = 0;
-	ts->flen = sizeof(Exec)+text;
+	ts->flen = text;
 	unlock(img);
 
 	/* Data. Shared. */