Call sites across the nvme-cli vendor plugins interpolate a caller-supplied path into a shell command string with no quoting and pass it to system(3). nvme-cli runs as root, so any principal that can invoke an affected subcommand with controlled arguments gets arbitrary command execution as root.
Proof of concept (not actually run):
nvme wdc vs-internal-log /dev/nvme0n1 -s 0x10000 -o '/tmp/a;chmod u+s $(command -v bash);#'
cmd_buf becomes:
tar --remove-files -czf /tmp/a;chmod u+s $(command -v bash);#.tar.gz /tmp/a;chmod u+s $(command -v bash);#
which /bin/sh splits into tar --remove-files -czf /tmp/a, then chmod u+s $(command -v bash) as root, then a comment. Result: setuid-root bash.
Don't do this. If you want to run a shell command sequence, then write a script to do it and let nvme-cli just do nvme stuff.
Call sites across the nvme-cli vendor plugins interpolate a caller-supplied path into a shell command string with no quoting and pass it to system(3). nvme-cli runs as root, so any principal that can invoke an affected subcommand with controlled arguments gets arbitrary command execution as root.
Proof of concept (not actually run):
cmd_buf becomes:
which /bin/sh splits into tar --remove-files -czf /tmp/a, then chmod u+s $(command -v bash) as root, then a comment. Result: setuid-root bash.
Don't do this. If you want to run a shell command sequence, then write a script to do it and let nvme-cli just do nvme stuff.