golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.63k stars 17.61k forks source link

syscall: special case `cmd.exe /c <command>` in StartProcess #69939

Open qmuntal opened 3 days ago

qmuntal commented 3 days ago

Background

It is well known that os/exec doesn't correctly escape nor quote *.bat, *.cmd, cmd /c * arguments. This is because in all three cases the escape/quote rules that apply are the ones defined in cmd.exe docs, which are slightly different than the ones os/exec and syscall.StartProcess follow, defined in parsing-c-command-line-arguments. This discrepancy causes bugs like #1849, #17149, #68313, and can also lead to security vulnerabilities.

The only workaround that exists today to reliably execute *.bat, *.cmd, cmd /c * command using os/exec is to manually escape/quote the arguments at caller site and pass the resulting string to syscall.SysProcAttr.CmdLine. The problem is that having a robust implementation is complicated, so projects tend to have half-backed solutions, if any.

Proposal

Special case %COMSPEC% /c <command> (%COMSPEC% usually points to cmd.exe) by applying the cmd.exe escape/quote rules to <command>. The exact rules are left for the implementer, as they are well documented.

Some considerations to take into account:

Why not special case also bat/cmd files

This proposal doesn't attempt to solve issues related to directly executing bat/cmd scripts for the following reasons:

Note that I'm not putting this proposal in the proposal process because it is not adding new API nor breaking existing behavior. It is more as an umbrella issue to discuss the design and the implementation.

@golang/security @golang/windows

gabyhelp commented 3 days ago

Related Issues and Documentation

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)