runtime: Process.Start() stuck forever on Alpine Linux when UserName is set in StartInfo

Code example:

using System;
using System.Diagnostics;

namespace test
{
    class Program
    {
        static void Main(string[] args)
        {
            var p = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/sh",
                    UserName = "root",
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false
                },
                EnableRaisingEvents = true
            };

            Console.WriteLine("Trying to start /bin/sh");
            p.Start();
            Console.WriteLine("/bin/sh started successfully");
        }
    }
}

Publish the project with dotnet publish -c Release -r linux-musl-x64 --self-contained and copy the output to a fresh-installed Alpine Linux VM.

localhost:~/test# ./test
Trying to start /bin/sh

(output stuck here)

The process tree looks like this image

localhost:~# cat /proc/2421/stack
[<0>] _do_fork+0x21c/0x2fe
[<0>] do_syscall_64+0x50/0xeb
[<0>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[<0>] 0xffffffffffffffff
localhost:~# cat /proc/2429/stack
[<0>] futex_wait_queue_me+0xbc/0x101
[<0>] futex_wait+0xd7/0x1f1
[<0>] do_futex+0x131/0x9a5
[<0>] __se_sys_futex+0x139/0x15e
[<0>] do_syscall_64+0x50/0xeb
[<0>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[<0>] 0xffffffffffffffff

It seems that the parent process already called vfork() but child has not yet exec or exit, leaving the parent in the uninterruptible sleep state. Related framework code could possibly be here

Environment info .NET Core SDK version: 3.0.100 OS: Alpine Linux 3.10 latest

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 18 (17 by maintainers)

Commits related to this issue

Most upvoted comments

My current thinking is that we should probably do what you did in the emergency patch you’ve linked above. That means use fork when the credentials need to be set. Trying to be clever and depend on various details that are not part of the spec is a dangerous road. We may want to do the same thing for glibc.

I agree with @janvorli. The vfork change from https://github.com/dotnet/corefx/pull/33289 was purely an optimization, one I was concerned about at the time. If it’s causing problems, we should either revert the change wholesale, or be very generous in where we choose to use fork, only using vfork in situations we’re 100% sure we will never see another problem.

And we should aim to service this.