问题
I am reading output from another process which generates output (slow and infinite). Because I want to read this data in real-time I use "stdbuf -oL" (line-buffered, data is text). I do not have control of the generating process so I cannot modify the source to force flushing.
So far stdbuf works just fine, however the process uses SOCK_RAW and needs either to be run as root, have setuid(0) or the cap_net_raw
capability. When running as non-root with setuid or capabilities stdbuf seems to be ignored. Let me demonstrate the problem:
This is a simple writer:
#include <stdio.h>
#include <unistd.h>
int main(){
int i;
for ( i = 0;; i++){
fprintf(stdout, "%d\n", i);
sleep(1);
}
}
And a simple reader:
#include <stdio.h>
int main(){
char* line = NULL;
size_t n = 0;
while (getline(&line, &n, stdin) != -1 ) {
fputs(line, stdout);
}
}
As expected, by executing ./writer | ./reader
nothing shows up until the buffer is filled. Prepending stdbuf -oL
enables line-buffering and I get the lines into the reader:
% stdbuf -oL ./writer | ./reader
0
1
2
...
But if I add cap_net_raw+ep
it stops working:
% sudo setcap cap_net_raw+ep ./writer
% stdbuf -oL ./writer | ./reader
(no output)
The same behaviour is observed when using setuid:
% sudo chown root:root ./writer
% sudo chmod +s ./writer
% stdbuf -oL ./writer | ./reader
(no output)
I'm interested in understanding why this happens and how I can continue to use stdbuf without running as root. I admit that I do not fully understand what setuid is doing behind the scenes.
回答1:
From looking at the stdbuf source code it looks like it works by setting LD_PRELOAD. There are of course security concerns using LD_PRELOAD with setuid executables or sudo.
One suggestion I found was to disable the noatsecure selinux attribute for your executable.
Another, simpler, option would be to avoid stdbuf and simply call fflush(stdout)
from your source code directly.
回答2:
Solution without LD_PRELOAD
You can use the unbuffer utility which is part of the expect (expect-devel
) package. unbuffer
is a very short expect script. It does not need LD_PRELOAD
because it uses another trick. expect
creates a pseudo terminal (like xterm
or ssh
) so the process executed using unbuffer
is fooled to think it is writing to an interactive device therefore by default it uses line buffering on stdout
.
Usage in your case:
unbuffer ./writer | ./reader
If stdbuf
works with the program unbuffer
would work with a high probability too. Because LD_PRELOAD
poses some limitations unbuffer
has advantages over stdbuf
. Contrary to stdbuf
it will work with these sorts of executables:
- setuid
- with file capabilities
- statically linked
- not using standard
libc
来源:https://stackoverflow.com/questions/13644024/stdbuf-with-setuid-capabilities