[Skiboot] [PATCH] opal-prd: handle devtmpfs mounted with noexec

Georgy Yakovlev gyakovlev at gentoo.org
Mon Oct 12 13:56:43 AEDT 2020


On 10/11/20 1:59 PM, Oliver O'Halloran wrote:
> On Sun, Oct 11, 2020 at 12:34 PM Georgy Yakovlev <gyakovlev at gentoo.org> wrote:
>>
>> Closes: https://github.com/open-power/skiboot/issues/258
> 
> Github / bugzilla links aren't a substitute for a commit message.
Thanks. Will update after/if we figure out the rest. More below.
> 
>> Signed-off-by: Georgy Yakovlev <gyakovlev at gentoo.org>
>> ---
>>   external/opal-prd/opal-prd.c | 39 ++++++++++++++++++++++++++++++++++--
>>   1 file changed, 37 insertions(+), 2 deletions(-)
>>
>> diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
>> index d74d8039..eb9a0b38 100644
>> --- a/external/opal-prd/opal-prd.c
>> +++ b/external/opal-prd/opal-prd.c
>> @@ -973,7 +973,10 @@ static int map_hbrt_file(struct opal_prd_ctx *ctx, const char *name)
>>   static int map_hbrt_physmem(struct opal_prd_ctx *ctx, const char *name)
>>   {
>>          struct prd_range *range;
>> +       int rc;
>>          void *buf;
>> +       void *ro_buf;
>> +       void *rwx_buf;
>>
>>          range = find_range(name, 0);
>>          if (!range) {
>> @@ -981,15 +984,47 @@ static int map_hbrt_physmem(struct opal_prd_ctx *ctx, const char *name)
>>                  return -1;
>>          }
>>
>> -       buf = mmap(NULL, range->size, PROT_READ | PROT_WRITE | PROT_EXEC,
>> +       ro_buf = mmap(NULL, range->size, PROT_READ,
>>                          MAP_PRIVATE, ctx->fd, range->physaddr);
>> -       if (buf == MAP_FAILED) {
>> +       if (ro_buf == MAP_FAILED) {
>>                  pr_log(LOG_ERR, "IMAGE: mmap(range:%s, "
>>                                  "phys:0x%016lx, size:0x%016lx) failed: %m",
>>                                  name, range->physaddr, range->size);
>>                  return -1;
>>          }
>>
>> +       rwx_buf = mmap(NULL, range->size, PROT_WRITE,
>> +                       MAP_SHARED | MAP_ANONYMOUS, -1 , 0);
>> +       if (rwx_buf == MAP_FAILED) {
>> +               pr_log(LOG_ERR, "IMAGE: anon mmap(size:0x%016lx) failed: %m",
>> +                               range->size);
>> +               return -1;
>> +       }
>> +
> 
>> +       buf = memcpy(rwx_buf, ro_buf, range->size);
>> +       if (!buf) {
> 
> memcpy() just returns the dest pointer so the condition will never be
> hit unless rwx_buf is NULL to begin with.
So don't check it at all? I see it called in other places with no checking.

> 
>> +               pr_log(LOG_ERR, "IMAGE: memcpy(dest:%p, "
>> +                               "src: %p, size:0x%016lx) failed: %m",
>> +                               rwx_buf, ro_buf, range->size);
>> +               return -1;
>> +       }
>> +
>> +       rc = munmap(ro_buf, range->size);
>> +       if (rc < 0) {
>> +               pr_log(LOG_ERR, "IMAGE: munmap("
>> +                               "phys:0x%016lx, size:0x%016lx) failed: %m",
>> +                               range->physaddr, range->size);
>> +               return -1;
>> +       }
>> +
>> +       rc = mprotect(buf, range->size, PROT_READ | PROT_WRITE | PROT_EXEC);
> 
> This should be PROT_READ | PROT_EXEC. You almost never want memory to
> be writable and executable at the same time. There's some legitimate
> uses for W+X memory (mainly JITs), but for the most part it just gives
> people writing exploits a convenient place to drop shellcode.

I'm afraid not, but not sure.
Original code maps it as rwx and afaik it tries to do something that 
requires write perms, but I can't figure it out myself.

If I remove PROT_WRITE it will segfault in call_hbrt_init() with SEGV_ACCERR

(gdb) bt
#0  0x00007ffff748016c in ?? ()
#1  0x000000010000abc8 in call_be ()
#2  0x0000000100005448 in hservices_init (ctx=0x7fffffffd250, 
code=0x7ffff7480000) at opal-prd.c:897
#3  0x0000000100009380 in run_prd_daemon (ctx=0x7fffffffd250) at 
opal-prd.c:2287
#4  0x000000010000a914 in main (argc=3, argv=0x7fffffffd728) at 
opal-prd.c:2746


write(1, "IMAGE: calling ibm,hbrt_init()\n", 31IMAGE: calling 
ibm,hbrt_init()
) = 31
switch_endian()                         = 4963763352
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, 
si_addr=0x7fff95ca2008} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault

this leads to thunk.S and I'm helpless there.


> 
>> +       if (rc < 0) {
>> +               pr_log(LOG_ERR, "IMAGE: mprotect(phys:%p, "
>> +                       "size:0x%016lx, rwx) failed: %m",
>> +                       buf, range->size);
>> +               return -1;
>> +       }
>> +
>>          ctx->code_addr = buf;
>>          ctx->code_size = range->size;
>>          return 0;
>> --
>> 2.28.0
>>
>> _______________________________________________
>> Skiboot mailing list
>> Skiboot at lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/skiboot



More information about the Skiboot mailing list