First, my suggested solution is presented below. After this, each of the two errors that you observed are discussed.
Suggested Solution
Bash variables cannot hold a NUL character. Consequently, it is only possible to read an entire file into a bash variable if the file contains no such characters. Subject to this bash limitation, the following should work for you:
$ echo aaa | { read -rd "" v; echo "$v"; } aaa
With read -d '' var, bash will read stdin until a NUL character is found. Since bash variables cannot contain NUL characters anyway, this approach does not limit you beyond the inherent limitations of bash.
The -r option to read prevents bash from interpreting backslash sequences. Also, if you want to preserve leading and trailing whitespace, then add IFS= before the read statement.
"try to read from fd: silently fails"
# echo aaa | sudo -u nobody bash -c 'echo $(<&0)' #
The above silent failure happens even without sudo:
$ echo aaa | bash -c 'echo $(<&0)' $
It even happens without creating the subshell:
$ echo aaa | echo $(<&0) $
The problem is that &0 is not a valid file name. Observe:
$ echo aaa | cat &0 [1] 22635 bash: 0: command not found
In bash, &0 is only meaningful when combined with < or >.
Let's look again at the bash documentation:
The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).
Since cat &0 does not work, one should not expect $(< &0) to work either.
"different user. fail"
This might seem like a reasonable thing to do:
# echo aaa | sudo -u nobody bash -c 'echo $(cat /dev/stdin)' cat: /dev/stdin: Permission denied
To see why it fails, let's examine the permissions of /dev/stdin:
# echo aaa | sudo -u nobody bash -c 'ls -lH /dev/stdin' prw------- 1 root root 0 Jul 1 15:42 /dev/stdin
User nobody does not have permission to access that file. This is reasonable: one doesn't want user nobody messing with root's files.
A 'smarter' operating system might know that nobody has access to /dev/stdin in this particular case but, for security purposes, it is probably good that the operating system does not try to out-smart itself.
/proc/$$/fd/0would fulfill your purpose./proc/self/fd/0. Same permission deniedsudorequirement.