sim: syscall: fix argvlen & argv implementation
authorMike Frysinger <vapier@gentoo.org>
Tue, 16 Nov 2021 05:03:50 +0000 (00:03 -0500)
committerMike Frysinger <vapier@gentoo.org>
Tue, 16 Nov 2021 07:09:46 +0000 (02:09 -0500)
Now that we have access to the argv & envp strings, finish implementing
these syscalls.  Delete unused variables, fix tbuf by incrementing the
pointer instead of setting to the length, and make sure we don't write
more data than the bufsize says is available.

sim/common/syscall.c

index e353d862504a93306c9d70e18139ded02a145af9..bad3b3b6214d494788198e77fe9369e420aaa673 100644 (file)
@@ -141,16 +141,14 @@ cb_syscall (host_callback *cb, CB_SYSCALL *sc)
 
   switch (cb_target_to_host_syscall (cb, sc->func))
     {
-#if 0 /* FIXME: wip */
     case CB_SYS_argvlen :
       {
        /* Compute how much space is required to store the argv,envp
           strings so that the program can allocate the space and then
           call SYS_argv to fetch the values.  */
-       int addr_size = cb->addr_size;
-       int argc,envc,arglen,envlen;
-       const char **argv = cb->init_argv;
-       const char **envp = cb->init_envp;
+       int argc, envc, arglen, envlen;
+       char **argv = cb->argv;
+       char **envp = cb->envp;
 
        argc = arglen = 0;
        if (argv)
@@ -164,7 +162,7 @@ cb_syscall (host_callback *cb, CB_SYSCALL *sc)
            for ( ; envp[envc]; ++envc)
              envlen += strlen (envp[envc]) + 1;
          }
-       result = arglen + envlen;
+       result = arglen + 1 + envlen + 1;
        break;
       }
 
@@ -174,63 +172,73 @@ cb_syscall (host_callback *cb, CB_SYSCALL *sc)
        TADDR tbuf = sc->arg1;
        /* Buffer size.  */
        int bufsize = sc->arg2;
+       int written = 0;
        /* Q is the target address of where all the strings go.  */
        TADDR q;
-       int word_size = cb->word_size;
-       int i,argc,envc,len;
-       const char **argv = cb->init_argv;
-       const char **envp = cb->init_envp;
+       int i, argc, envc, len, ret;
+       char **argv = cb->argv;
+       char **envp = cb->envp;
+
+       result = -1;
 
        argc = 0;
        if (argv)
          {
            for ( ; argv[argc]; ++argc)
              {
-               int len = strlen (argv[argc]);
-               int written = (*sc->write_mem) (cb, sc, tbuf, argv[argc], len + 1);
-               if (written != len)
-                 {
-                   result = -1;
-                   errcode = EINVAL;
-                   goto FinishSyscall;
-                 }
-               tbuf = len + 1;
+               len = strlen (argv[argc]) + 1;
+               if (written + len > bufsize)
+                 goto efault;
+
+               ret = (*sc->write_mem) (cb, sc, tbuf + written, argv[argc],
+                                       len);
+               if (ret != len)
+                 goto einval;
+
+               written += ret;
              }
          }
-       if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
-         {
-           result = -1;
-           errcode = EINVAL;
-           goto FinishSyscall;
-         }
-       tbuf++;
+       /* Double NUL bytes indicates end of strings.  */
+       if (written >= bufsize)
+         goto efault;
+       if ((*sc->write_mem) (cb, sc, tbuf + written, "", 1) != 1)
+         goto einval;
+       ++written;
+
        envc = 0;
        if (envp)
          {
            for ( ; envp[envc]; ++envc)
              {
-               int len = strlen (envp[envc]);
-               int written = (*sc->write_mem) (cb, sc, tbuf, envp[envc], len + 1);
-               if (written != len)
-                 {
-                   result = -1;
-                   errcode = EINVAL;
-                   goto FinishSyscall;
-                 }
-               tbuf = len + 1;
+               len = strlen (envp[envc]) + 1;
+               if (written + len > bufsize)
+                 goto efault;
+
+               ret = (*sc->write_mem) (cb, sc, tbuf + written, envp[envc],
+                                       len);
+               if (ret != len)
+                 goto einval;
+               written += ret;
              }
          }
-       if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
-         {
-           result = -1;
-           errcode = EINVAL;
-           goto FinishSyscall;
-         }
+       /* Double NUL bytes indicates end of strings.  */
+       if (written >= bufsize)
+         goto efault;
+       if ((*sc->write_mem) (cb, sc, tbuf + written, "", 1) != 1)
+         goto einval;
+
        result = argc;
        sc->result2 = envc;
        break;
+
+ efault:
+       errcode = EFAULT;
+       goto FinishSyscall;
+
+ einval:
+       errcode = EINVAL;
+       goto FinishSyscall;
       }
-#endif /* wip */
 
     case CB_SYS_exit :
       /* Caller must catch and handle; see sim_syscall as an example.  */