Change /proc/PID/cmdline to read environment vector.
- Change proc to return envp on overwrite of argv with limitations from upstream. - Add unit tests - Change layout of argv/envp on the stack so that end of argv is contiguous with beginning of envp. PiperOrigin-RevId: 232506107 Change-Id: I993880499ab2c1220f6dc456a922235c49304dec
This commit is contained in:
parent
3eae03fe4f
commit
0cf7fc4e11
|
@ -170,6 +170,24 @@ func (s *Stack) Load(args []string, env []string, aux Auxv) (StackLayout, error)
|
||||||
// Make sure we start with a 16-byte alignment.
|
// Make sure we start with a 16-byte alignment.
|
||||||
s.Align(16)
|
s.Align(16)
|
||||||
|
|
||||||
|
// Push the environment vector so the end of the argument vector is adjacent to
|
||||||
|
// the beginning of the environment vector.
|
||||||
|
// While the System V abi for x86_64 does not specify an ordering to the
|
||||||
|
// Information Block (the block holding the arg, env, and aux vectors),
|
||||||
|
// support features like setproctitle(3) naturally expect these segments
|
||||||
|
// to be in this order. See: https://www.uclibc.org/docs/psABI-x86_64.pdf
|
||||||
|
// page 29.
|
||||||
|
l.EnvvEnd = s.Bottom
|
||||||
|
envAddrs := make([]usermem.Addr, len(env))
|
||||||
|
for i := len(env) - 1; i >= 0; i-- {
|
||||||
|
addr, err := s.Push(env[i])
|
||||||
|
if err != nil {
|
||||||
|
return StackLayout{}, err
|
||||||
|
}
|
||||||
|
envAddrs[i] = addr
|
||||||
|
}
|
||||||
|
l.EnvvStart = s.Bottom
|
||||||
|
|
||||||
// Push our strings.
|
// Push our strings.
|
||||||
l.ArgvEnd = s.Bottom
|
l.ArgvEnd = s.Bottom
|
||||||
argAddrs := make([]usermem.Addr, len(args))
|
argAddrs := make([]usermem.Addr, len(args))
|
||||||
|
@ -182,18 +200,6 @@ func (s *Stack) Load(args []string, env []string, aux Auxv) (StackLayout, error)
|
||||||
}
|
}
|
||||||
l.ArgvStart = s.Bottom
|
l.ArgvStart = s.Bottom
|
||||||
|
|
||||||
// Push our environment.
|
|
||||||
l.EnvvEnd = s.Bottom
|
|
||||||
envAddrs := make([]usermem.Addr, len(env))
|
|
||||||
for i := len(env) - 1; i >= 0; i-- {
|
|
||||||
addr, err := s.Push(env[i])
|
|
||||||
if err != nil {
|
|
||||||
return StackLayout{}, err
|
|
||||||
}
|
|
||||||
envAddrs[i] = addr
|
|
||||||
}
|
|
||||||
l.EnvvStart = s.Bottom
|
|
||||||
|
|
||||||
// We need to align the arguments appropriately.
|
// We need to align the arguments appropriately.
|
||||||
//
|
//
|
||||||
// We must finish on a 16-byte alignment, but we'll play it
|
// We must finish on a 16-byte alignment, but we'll play it
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package proc
|
package proc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
@ -139,20 +140,62 @@ func (f *execArgFile) Read(ctx context.Context, _ *fs.File, dst usermem.IOSequen
|
||||||
// N.B. Technically this should be usermem.IOOpts.IgnorePermissions = true
|
// N.B. Technically this should be usermem.IOOpts.IgnorePermissions = true
|
||||||
// until Linux 4.9 (272ddc8b3735 "proc: don't use FOLL_FORCE for reading
|
// until Linux 4.9 (272ddc8b3735 "proc: don't use FOLL_FORCE for reading
|
||||||
// cmdline and environment").
|
// cmdline and environment").
|
||||||
copyN, copyErr := m.CopyIn(ctx, start, buf, usermem.IOOpts{})
|
copyN, err := m.CopyIn(ctx, start, buf, usermem.IOOpts{})
|
||||||
if copyN == 0 {
|
if copyN == 0 {
|
||||||
// Nothing to copy.
|
// Nothing to copy.
|
||||||
return 0, copyErr
|
return 0, err
|
||||||
}
|
}
|
||||||
buf = buf[:copyN]
|
buf = buf[:copyN]
|
||||||
|
|
||||||
// TODO: On Linux, if the NUL byte at the end of the
|
// On Linux, if the NUL byte at the end of the argument vector has been
|
||||||
// argument vector has been overwritten, it continues reading the
|
// overwritten, it continues reading the environment vector as part of
|
||||||
// environment vector as part of the argument vector.
|
// the argument vector.
|
||||||
|
|
||||||
|
if f.arg == cmdlineExecArg && buf[copyN-1] != 0 {
|
||||||
|
// Linux will limit the return up to and including the first null character in argv
|
||||||
|
|
||||||
|
copyN = bytes.IndexByte(buf, 0)
|
||||||
|
if copyN == -1 {
|
||||||
|
copyN = len(buf)
|
||||||
|
}
|
||||||
|
// If we found a NUL character in argv, return upto and including that character.
|
||||||
|
if copyN < len(buf) {
|
||||||
|
buf = buf[:copyN]
|
||||||
|
} else { // Otherwise return into envp.
|
||||||
|
lengthEnvv := int(m.EnvvEnd() - m.EnvvStart())
|
||||||
|
|
||||||
|
// Upstream limits the returned amount to one page of slop.
|
||||||
|
// https://elixir.bootlin.com/linux/v4.20/source/fs/proc/base.c#L208
|
||||||
|
// we'll return one page total between argv and envp because of the
|
||||||
|
// above page restrictions.
|
||||||
|
if lengthEnvv > usermem.PageSize-len(buf) {
|
||||||
|
lengthEnvv = usermem.PageSize - len(buf)
|
||||||
|
}
|
||||||
|
// Make a new buffer to fit the whole thing
|
||||||
|
tmp := make([]byte, length+lengthEnvv)
|
||||||
|
copyNE, err := m.CopyIn(ctx, m.EnvvStart(), tmp[copyN:], usermem.IOOpts{})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux will return envp up to and including the first NUL character, so find it.
|
||||||
|
for i, c := range tmp[copyN:] {
|
||||||
|
if c == 0 {
|
||||||
|
copyNE = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(tmp, buf)
|
||||||
|
buf = tmp[:copyN+copyNE]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
n, dstErr := dst.CopyOut(ctx, buf)
|
n, dstErr := dst.CopyOut(ctx, buf)
|
||||||
if dstErr != nil {
|
if dstErr != nil {
|
||||||
return int64(n), dstErr
|
return int64(n), dstErr
|
||||||
}
|
}
|
||||||
return int64(n), copyErr
|
return int64(n), err
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ class ExecveArray {
|
||||||
ExecveArray& operator=(ExecveArray&&) = delete;
|
ExecveArray& operator=(ExecveArray&&) = delete;
|
||||||
|
|
||||||
char* const* get() const { return ptrs_.data(); }
|
char* const* get() const { return ptrs_.data(); }
|
||||||
|
size_t get_size() { return str_.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<char> str_;
|
std::vector<char> str_;
|
||||||
|
|
Loading…
Reference in New Issue