Message ID | 20171219115041.6611-1-syq@debian.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Le 19/12/2017 à 12:50, YunQiang Su a écrit : > MIPS r6 is not just simple super set for pre-R6, > it also drops some instruction and even changes encoding for some. > But r6 binary has the same header for binfmt_misc. > So here we need to detect the version of binaries and set > cpu_model for it. > --- > include/elf.h | 4 ++++ > linux-user/elfload.c | 36 ++++++++++++++++++++++++++++++++++++ > linux-user/main.c | 15 +++++++++++++++ > linux-user/qemu.h | 1 + > 4 files changed, 56 insertions(+) > > diff --git a/include/elf.h b/include/elf.h > index e8a515ce3d..f2104809b1 100644 > --- a/include/elf.h > +++ b/include/elf.h > @@ -40,6 +40,10 @@ typedef int64_t Elf64_Sxword; > #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ > #define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ > #define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ > +#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ > +#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ > +#define EF_MIPS_ARCH_32R6 0x90000000 /* MIPS32r6 code. */ > +#define EF_MIPS_ARCH_64R6 0xa0000000 /* MIPS64r6 code. */ > > /* The ABI of a file. */ > #define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ > diff --git a/linux-user/elfload.c b/linux-user/elfload.c > index 20f3d8c2c3..f9b8e028ca 100644 > --- a/linux-user/elfload.c > +++ b/linux-user/elfload.c > @@ -2224,6 +2224,42 @@ static void load_elf_interp(const char *filename, struct image_info *info, > exit(-1); > } > > +uint32_t get_elf_eflags(const char *filename) > +{ > + int fd, retval; > + char bprm_buf[BPRM_BUF_SIZE]; > + > + fd = open(path(filename), O_RDONLY); You can't do that with binfmt and credential ('C' flag) enabled (it implies 'O' flag, open-binary), because in this case the kernel opens the file and provides the file descriptor to QEMU. We need the 'C' flags to allow to execute binaries with the setuid flag (like "sudo") [1] See linux-user/main.c: 4446 execfd = qemu_getauxval(AT_EXECFD); 4447 if (execfd == 0) { 4448 execfd = open(filename, O_RDONLY); 4449 if (execfd < 0) { 4450 printf("Error while loading %s: %s\n", filename, strerror(errno)); 4451 _exit(EXIT_FAILURE); 4452 } 4453 } Thanks, Laurent [1] https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/binfmt-misc.rst
should something like: + int fd, retval; + off_t cur_pos; + bool is_execfd = true; + char bprm_buf[BPRM_BUF_SIZE]; + + fd = qemu_getauxval(AT_EXECFD); + if (fd == 0){ + is_execfd = false; + fd = open(path(filename), O_RDONLY); + if (fd < 0) { + return 0; + } + }else{ + cur_pos = lseek(fd, 0, SEEK_CUR); + if ((cur_pos < 0) || (lseek(fd, 0, SEEK_SET) != 0)){ + printf("Error while lseek in %s: %s\n", filename, strerror(errno)); + _exit(EXIT_FAILURE); + } + } + retval = read(fd, bprm_buf, BPRM_BUF_SIZE); + if (!is_execfd) + close(fd); + else { + if (lseek(fd, cur_pos, SEEK_SET) != cur_pos){ + printf("Error while lseek in %s: %s\n", filename, strerror(errno)); + _exit(EXIT_FAILURE); + } + } + + if (retval < 0) { + return 0; + } works? On Sun, Dec 24, 2017 at 12:34 AM, Laurent Vivier <laurent@vivier.eu> wrote: > Le 19/12/2017 à 12:50, YunQiang Su a écrit : >> MIPS r6 is not just simple super set for pre-R6, >> it also drops some instruction and even changes encoding for some. >> But r6 binary has the same header for binfmt_misc. >> So here we need to detect the version of binaries and set >> cpu_model for it. >> --- >> include/elf.h | 4 ++++ >> linux-user/elfload.c | 36 ++++++++++++++++++++++++++++++++++++ >> linux-user/main.c | 15 +++++++++++++++ >> linux-user/qemu.h | 1 + >> 4 files changed, 56 insertions(+) >> >> diff --git a/include/elf.h b/include/elf.h >> index e8a515ce3d..f2104809b1 100644 >> --- a/include/elf.h >> +++ b/include/elf.h >> @@ -40,6 +40,10 @@ typedef int64_t Elf64_Sxword; >> #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ >> #define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ >> #define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ >> +#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ >> +#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ >> +#define EF_MIPS_ARCH_32R6 0x90000000 /* MIPS32r6 code. */ >> +#define EF_MIPS_ARCH_64R6 0xa0000000 /* MIPS64r6 code. */ >> >> /* The ABI of a file. */ >> #define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ >> diff --git a/linux-user/elfload.c b/linux-user/elfload.c >> index 20f3d8c2c3..f9b8e028ca 100644 >> --- a/linux-user/elfload.c >> +++ b/linux-user/elfload.c >> @@ -2224,6 +2224,42 @@ static void load_elf_interp(const char *filename, struct image_info *info, >> exit(-1); >> } >> >> +uint32_t get_elf_eflags(const char *filename) >> +{ >> + int fd, retval; >> + char bprm_buf[BPRM_BUF_SIZE]; >> + >> + fd = open(path(filename), O_RDONLY); > > You can't do that with binfmt and credential ('C' flag) enabled (it > implies 'O' flag, open-binary), because in this case the kernel opens > the file and provides the file descriptor to QEMU. We need the 'C' flags > to allow to execute binaries with the setuid flag (like "sudo") [1] > > See linux-user/main.c: > > 4446 execfd = qemu_getauxval(AT_EXECFD); > 4447 if (execfd == 0) { > 4448 execfd = open(filename, O_RDONLY); > 4449 if (execfd < 0) { > 4450 printf("Error while loading %s: %s\n", filename, > strerror(errno)); > 4451 _exit(EXIT_FAILURE); > 4452 } > 4453 } > > Thanks, > Laurent > [1] > https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/binfmt-misc.rst
Peter, Riku, what do you think of the idea of using the ELF header to select the CPU to emulate? Thanks, Laurent Le 19/12/2017 à 12:50, YunQiang Su a écrit : > MIPS r6 is not just simple super set for pre-R6, > it also drops some instruction and even changes encoding for some. > But r6 binary has the same header for binfmt_misc. > > So here we need to detect the version of binaries and set > cpu_model for it. > --- > include/elf.h | 4 ++++ > linux-user/elfload.c | 36 ++++++++++++++++++++++++++++++++++++ > linux-user/main.c | 15 +++++++++++++++ > linux-user/qemu.h | 1 + > 4 files changed, 56 insertions(+) > > diff --git a/include/elf.h b/include/elf.h > index e8a515ce3d..f2104809b1 100644 > --- a/include/elf.h > +++ b/include/elf.h > @@ -40,6 +40,10 @@ typedef int64_t Elf64_Sxword; > #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ > #define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ > #define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ > +#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ > +#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ > +#define EF_MIPS_ARCH_32R6 0x90000000 /* MIPS32r6 code. */ > +#define EF_MIPS_ARCH_64R6 0xa0000000 /* MIPS64r6 code. */ > > /* The ABI of a file. */ > #define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ > diff --git a/linux-user/elfload.c b/linux-user/elfload.c > index 20f3d8c2c3..f9b8e028ca 100644 > --- a/linux-user/elfload.c > +++ b/linux-user/elfload.c > @@ -2224,6 +2224,42 @@ static void load_elf_interp(const char *filename, struct image_info *info, > exit(-1); > } > > +uint32_t get_elf_eflags(const char *filename) > +{ > + int fd, retval; > + char bprm_buf[BPRM_BUF_SIZE]; > + > + fd = open(path(filename), O_RDONLY); > + if (fd < 0) { > + return 0; > + } > + retval = read(fd, bprm_buf, BPRM_BUF_SIZE); > + close(fd); > + if (retval < 0) { > + return 0; > + } > + if (retval < BPRM_BUF_SIZE) { > + memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval); > + } > + > + if (bprm_buf[0] != 0x7f > + || bprm_buf[1] != 'E' > + || bprm_buf[2] != 'L' > + || bprm_buf[3] != 'F') { > + return 0; > + } > + > + struct elfhdr *ehdr = (struct elfhdr *)bprm_buf; > + if (!elf_check_ident(ehdr)) { > + return 0; > + } > + bswap_ehdr(ehdr); > + if (!elf_check_ehdr(ehdr)) { > + return 0; > + } > + return ehdr->e_flags; > +} > + > static int symfind(const void *s0, const void *s1) > { > target_ulong addr = *(target_ulong *)s0; > diff --git a/linux-user/main.c b/linux-user/main.c > index 7c0bffeff6..b4626e5aa0 100644 > --- a/linux-user/main.c > +++ b/linux-user/main.c > @@ -4287,6 +4287,21 @@ int main(int argc, char **argv, char **envp) > } > trace_init_file(trace_file); > > +#if defined(TARGET_MIPS) > + if (cpu_model == NULL) { > + uint32_t eflags = get_elf_eflags(filename); > +#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) > + if ((eflags & EF_MIPS_ARCH_64R6) != 0) { > + cpu_model = "I6400"; > + } > +#else > + if ((eflags & EF_MIPS_ARCH_32R6) != 0) { > + cpu_model = "mips32r6-generic"; > + } > +#endif > + } > +#endif > + > /* Zero out regs */ > memset(regs, 0, sizeof(struct target_pt_regs)); > > diff --git a/linux-user/qemu.h b/linux-user/qemu.h > index 4edd7d0c08..cf09110bf9 100644 > --- a/linux-user/qemu.h > +++ b/linux-user/qemu.h > @@ -190,6 +190,7 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, > > int load_elf_binary(struct linux_binprm *bprm, struct image_info *info); > int load_flt_binary(struct linux_binprm *bprm, struct image_info *info); > +uint32_t get_elf_eflags(const char *filename); > > abi_long memcpy_to_target(abi_ulong dest, const void *src, > unsigned long len); >
On 01/08/2018 03:34 PM, Laurent Vivier wrote: > Peter, Riku, > > what do you think of the idea of using the ELF header to select the CPU > to emulate? I think it's a good way to cut down on mistakes and reduce -- or at least not increase -- the number of binaries we build. r~
Signed-off-by: YunQiang Su <syq@debian.org> On Tue, Jan 9, 2018 at 11:39 PM, Richard Henderson <richard.henderson@linaro.org> wrote: > On 01/08/2018 03:34 PM, Laurent Vivier wrote: >> Peter, Riku, >> >> what do you think of the idea of using the ELF header to select the CPU >> to emulate? > > I think it's a good way to cut down on mistakes and reduce -- or at least not > increase -- the number of binaries we build. > > > r~
diff --git a/include/elf.h b/include/elf.h index e8a515ce3d..f2104809b1 100644 --- a/include/elf.h +++ b/include/elf.h @@ -40,6 +40,10 @@ typedef int64_t Elf64_Sxword; #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ #define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ +#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ +#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ +#define EF_MIPS_ARCH_32R6 0x90000000 /* MIPS32r6 code. */ +#define EF_MIPS_ARCH_64R6 0xa0000000 /* MIPS64r6 code. */ /* The ABI of a file. */ #define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 20f3d8c2c3..f9b8e028ca 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2224,6 +2224,42 @@ static void load_elf_interp(const char *filename, struct image_info *info, exit(-1); } +uint32_t get_elf_eflags(const char *filename) +{ + int fd, retval; + char bprm_buf[BPRM_BUF_SIZE]; + + fd = open(path(filename), O_RDONLY); + if (fd < 0) { + return 0; + } + retval = read(fd, bprm_buf, BPRM_BUF_SIZE); + close(fd); + if (retval < 0) { + return 0; + } + if (retval < BPRM_BUF_SIZE) { + memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval); + } + + if (bprm_buf[0] != 0x7f + || bprm_buf[1] != 'E' + || bprm_buf[2] != 'L' + || bprm_buf[3] != 'F') { + return 0; + } + + struct elfhdr *ehdr = (struct elfhdr *)bprm_buf; + if (!elf_check_ident(ehdr)) { + return 0; + } + bswap_ehdr(ehdr); + if (!elf_check_ehdr(ehdr)) { + return 0; + } + return ehdr->e_flags; +} + static int symfind(const void *s0, const void *s1) { target_ulong addr = *(target_ulong *)s0; diff --git a/linux-user/main.c b/linux-user/main.c index 7c0bffeff6..b4626e5aa0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4287,6 +4287,21 @@ int main(int argc, char **argv, char **envp) } trace_init_file(trace_file); +#if defined(TARGET_MIPS) + if (cpu_model == NULL) { + uint32_t eflags = get_elf_eflags(filename); +#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) + if ((eflags & EF_MIPS_ARCH_64R6) != 0) { + cpu_model = "I6400"; + } +#else + if ((eflags & EF_MIPS_ARCH_32R6) != 0) { + cpu_model = "mips32r6-generic"; + } +#endif + } +#endif + /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 4edd7d0c08..cf09110bf9 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -190,6 +190,7 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, int load_elf_binary(struct linux_binprm *bprm, struct image_info *info); int load_flt_binary(struct linux_binprm *bprm, struct image_info *info); +uint32_t get_elf_eflags(const char *filename); abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len);