Is sys.stderr a block device or character device in Python3? - python

In C language, if I write codes like this:
#include <stdio.h>
#include <unistd.h>
int main()
{
while(1)
{
fprintf(stdout,"hello-std-out");
fprintf(stderr,"hello-std-err");
sleep(1);
}
return 0;
}
The stdout will not be displayed because it's a block device. But stderr will be displayed because it's not.
However, if I write similar codes in Python3:
import sys
import time
if __name__ == '__main__':
while True:
sys.stdout.write("hello-std-out")
sys.stderr.write("hello-stderr")
time.sleep(1)
Both stdout and stderr will not be displayed if I don't flush these buffers. Does that mean sys.stderr is also a block device in Python?

If you don't see stderr then you are on Python3 where text IO layer is line-bufferred when connected to a tty and block-bufferred otherwise regardless -u option.
The bufferring issues are unrelated to character/block devices.

Related

How can I make a linux background process (in c) that launches a Python script

I made a Linux background process (in c++) that monitors a directory and attempts to launch a Python script if a certain file appears in that directory. My issue is that the child process responsible for launching the Python script exits immediately after the execvp function is called and I can't understand why. All of the necessary files are under root's ownership. Here is my code if it helps. Thank you in advance for any pointers! I have marked the error in my code where the error occurs. I have also included the Python script to be called
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
using namespace std;
char* arguments[3];
FILE* fd;
const char* logFilePath = "/home/BluetoothProject/Logs/fileMonitorLogs.txt";
char* rfcommPath = (char*)"/home/BluetoothProject/RFCOMMOut.py";
void logToFile(const char*);
void doWork();
void logToFile(const char* str) {
fd = fopen(logFilePath, "a");
fprintf(fd, "%s\n", str);
fclose(fd);
}
int main() {
arguments[0] = (char*)"python";
arguments[1] = rfcommPath;
arguments[2] = NULL;
pid_t pid = fork();
if(pid < 0) {
printf("Fork failed");
exit(1);
} else if(pid > 0) {
exit(EXIT_SUCCESS);
}
umask(0);
pid_t sid = setsid();
if(sid < 0) {
logToFile("setsid() didn't work.");
exit(1);
}
if ((chdir("/")) < 0) {
logToFile("chdir() didn't work.");
exit(EXIT_FAILURE);
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
doWork();
}
void doWork() {
pid_t pid = fork();
if(pid < 0) {
logToFile("doWork() fork didn't work.");
} else if(pid > 0) {
int status = 0;
waitpid(pid, &status, 0);
if(WEXITSTATUS(status) == 1) {
logToFile("Child process exited with an error.");
}
} else {
int error = execvp(arguments[0], arguments); //Here is where the error is
if(error == -1) {
logToFile("execvp() failed.");
}
exit(1);
}
}
Python script (AKA RFCOMMOut.py)
import RPi.GPIO as gpio
import serial
led_state = 0
led_pin = 11
gpio.setmode(gpio.BOARD)
gpio.setwarnings(False)
gpio.setup(led_pin, gpio.OUT)
try:
ser = serial.Serial(port = '/dev/rfcomm0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS)
except IOException as e:
logFile = open("/home/BluetoothProject/Logs/fileMonitorLogs.txt", "a")
logFile.write("(First error handler) There was an exception:\n")
logFile.write(str(e))
logFile.write("\n")
logFile.close()
#gpio.output
def process_input(input):
global led_state
if input == "I have been sent.\n":
if led_state == 1:
led_state = 0
gpio.output(led_pin, led_state)
else:
led_state = 1
gpio.output(led_pin, led_state)
while True:
try:
transmission = ser.readline()
process_input(transmission)
except IOError as e:
logFile = open("/home/BluetoothProject/Logs/fileMonitorLogs.txt", "a")
logFile.write("(second error handler) There was an exception:\n")
logFile.write(str(e))
logFile.write("\n")
logFile.close()
break
led_state = 0
gpio.output(led_pin, led_state)
gpio.cleanup()
print("End of program\n")
The question is a little unclear, so I'll try to take a few different educated guesses at what the problem is and address each one individually.
TL;DR: Remove close(STDOUT_FILENO) and close(STDERR_FILENO) to get more debugging information which will hopefully point you in the right direction.
execvp(3) is returning -1
According to the execvp(3) documentation, execvp(3) sets errno when it fails. In order to understand why it is failing, your program will need to output the value of errno somewhere; perhaps stdout, stderr, or your log file. A convenient way to do this is to use perror(3). For example:
#include <stdio.h>
...
void doWork() {
...
} else {
int error = execvp(arguments[0], arguments);
if(error == -1) {
perror("execvp() failed");
}
}
...
}
Without knowing what that errno value is, it will be difficult to identify why execvp(3) is failing.
execvp(3) is succeeding, but my Python program doesn't appear run
execvp(3) succeeding means that the Python interpreter has successfully been invoked (assuming that there is no program in your PATH that is named "python", but is not actually a Python interpreter). If your program doesn't appear to be running, that means Python is having difficulty loading your program. To my knowledge, Python will always output relevant error messages in this situation to stderr; for example, if Python cannot find your program, it will output "No such file or directory" to stderr.
However, it looks like your C program is calling close(STDERR_FILENO) before calling doWork(). According to fork(2), child processes inherit copies of their parent's set of open file descriptors. This means that calling close(STDERR_FILENO) before forking will result in the child process not having an open stderr file descriptor. If Python is having any errors executing your program, you'll never know, since Python is trying to notify you through a file descriptor that doesn't exist. If execvp(3) is succeeding and the Python program appears to not run at all, then I recommend you remove close(STDERR_FILENO) from your C program and run everything again. Without seeing the error message output by Python, it will be difficult to identify why it is failing to run the Python program.
As an aside, I recommend against explicitly closing stdin, stdout, and stderr. According to stdin(3), the standard streams are closed by a call to exit(3) and by normal program termination.
execvp(3) is succeeding, my Python program is running, but my Python program exits before it does any useful work
In this case, I'm not sure what the problem might be, since I'm not very familiar with Raspberry Pi. But I think you'll have an easier time debugging if you don't close the standard streams before running the Python program.
Hope this helps.

How to properly capture output of process using pwntools

I'm currently confused on how to use the pwntools library for python3 for exploiting programs - mainly sending the input into a vulnerable program.
This is my current python script.
from pwn import *
def executeVuln():
vulnBin = process("./buf2", stdin=PIPE, stdout=PIPE)
vulnBin.sendlineafter(': ','A'*90)
output = vulnBin.recvline(timeout=5)
print(output)
executeVuln()
The program I'm trying to exploit is below - This isn't about how to exploit the program, more on using the script to properly automate it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFSIZE 176
#define FLAGSIZE 64
void flag(unsigned int arg1, unsigned int arg2) {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f);
if (arg1 != 0xDEADBEEF)
return;
if (arg2 != 0xC0DED00D)
return;
printf(buf);
}
void vuln(){
char buf[BUFSIZE];
gets(buf);
puts(buf);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
gid_t gid = getegid();
setresgid(gid, gid, gid);
puts("Please enter your string: ");
vuln();
return 0;
}
The process is opened fine.
sendlineafter blocks until it sends the line and so if it doesn't match it waits indefinitely. However, it runs fine and so the input should be sent.
output should receive 90 A's from recvLine due to
puts(buffer) outputting the inputted string.
However, all that is returned is
b'', which seems to indicate that the vulnerable program isn't receiving the input and returning an empty string.
Anyone know what's causing this?
With the above programs, I'm getting the print(output) as b'\n' (not b'') and here is the explanation for it.
The puts() statement outputs a newline character at the end and it is not read by the sendlineafter() call, which in-turn leads the stray newline character to be read by the below recvline() printing b'\n'.
Why the newline character is not by read by sendlineafter()? Because the sendlineafter() is just a combination of recvuntil() and sendline(), where recvuntil() only reads till delimiter leaving characters after. (pwntools docs)
So the solution for this is to read the newline character with sendlineafter() like below (or by calling recvline() twice),
from pwn import *
def executeVuln():
vulnBin = process("./buf2", stdin=PIPE, stdout=PIPE)
vulnBin.sendlineafter(b': \n',b'A'*90)
output = vulnBin.recvline(timeout=5)
print(output)
executeVuln()
Output:
[+] Starting local process './buf2': pid 3493
[*] Process './buf2' stopped with exit code 0 (pid 3493)
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
Note:
I added the strings as bytes in sendlineafter() to remove the below BytesWarning.
program.py:5: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
vulnBin.sendlineafter(': \n','A'*90)

Getting extra data from named pipe, C program (writer) and Python (reader)

I have a C program that is writing to a named pipe which is just outputting strings and a "/n" character as a delimiter. When I read from this named pipe using another C program my string comes back as expected. I have a python script which is what I want to be reading the named pipe with. It get's the proper string but also outputs lots of other garage data along with it including device descriptors.
EDIT: I should note I'm working with named-pipes on linux
Here's the C program reader which works fine:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd;
char * myfifo = "/tmp/testpipe";
char buf[MAX_BUF];
while(1){
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
close(fd);
}
return 0;
}
and the python version:
import os
import errno
FIFO = '/tmp/testpipe'
try:
os.mkfifo(FIFO)
except OSError as oe:
if oe.errno != errno.EEXIST:
raise
while True:
with open(FIFO) as fifo:
for line in fifo:
print('{0}',line)
The output I'm getting is:
('{0}', 'systime=1523890481 ch=25 LAP=c969d3 err=0 clkn=286140 clk_offset=954 s=-68 n=-55 snr=-13\n')
('{0}', "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x97\xfav(\xdc\xf7~\xc0\xf3\xd1v\x96\x06\x00\x00,\xdc\xf7~$F\xf8v\x01\x00\x00\x00\xb4e\xd2v\x96\x06\x00\x00\x04\x88\xd2v\xa0\x97\xfav,\xdc\xf7~\x18\xdc\xf7~L\xdd\xf7~ \xdc\xf7~T\xdd\xf7~S\xed\xf7~ \xdc\xf7~\x00\x00\x00\x00\xff\x0f\x00\x00T\xdd\xf7~\xc8\xdc\xf7~\x01\x00\x00\x00P#L\x00\x00\x00\x00\x00D\xb9\xdfv\x00\x00\x00\x00L\xdd\xf7~\x01\x80\xad\xfbT\xdd\xf7~T\xdd\xf7~T\xdd\xf7~T\xdd\xf7~z\xdd\xf7~S\xed\xf7~T\xdd\xf7~S\xed\xf7~\x00\x00\x00\x00\xa0\x97\xfav\xc0\xdc\xf7~\xdc\xed\xd1v\x1d\x05\x00\x00\xc4\xdc\xf7~$F\xf8v\x01\x00\x00\x00$N\xd2v\x1d\x05\x00\x00\x04\x88\xd2v\xa0\x97\xfav\xc4\xdc\xf7~\xc0\xdc\xf7~\xff\xff\xff\xff\xf0\xac\xfav\x04\x88\xd2vT\xfc\xd1v\x06n\x0e\xc4ps \x06\x82\x0b\xf1v\x90\xf5\xf0v0\x89\xf9v\xf0\xac\xfav0\xdd\xf7~\x88\xb8\xfav\xbcr\xf9v\x00\xb0\xfav\x00\x00\x00\x00\x00W\xfav\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4\xdd\xf7~\x06n\x0e\xc4\xd0\x93\xfav\x00\x00\x00\x000\xdd\xf7~8\xdd\xf7~\xa4\xdd\xf7~\x82\x0b\xf1v\x8c\xdd\xf7~\xfcK\xf8v8\xdd\xf7~\xbc\xba\xfav\x05\x00\x00\x00XX\xfav\x05\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x18\x92\xfav\xe8\xac\xfav\xff\xff\xff\xff\x00\x00\x00\x00T\xdd\xf7~\x00\x00\x00\x00\xff\xff\xff\xff\xd0\x93\xfav\x18\x92\xfav\xff\xff\xff\xffp\xcc\xddv$N\xd2v\xa0\x97\xfav\xe0\x13\xf2v\xc8\x13\xf2v |M\x00\xd4 \xf2vD[\xe5v/sys\x00\x00\x00\x00/usb/devices/1-1\x00\xf0\xf0vl#\x02\x00\x01\x00\x00\x00`d\xfav\x00\x00\x00\x00P#L\x00\xf8\xdd\xf7~\x0c\x00\x00\x00\xe8\xa1\xf8vXX\xfav\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00/1-1$N\xd2v \xcaM\x00\x02\x00\x00\x00\xe8\xac\xfav \xcaM\x00\xf4\xdd\xf7~\xe8\xac\xfav\t\x00\x00\x00\x00\x00\x00\x00P#L\x00p\xcc\xddv\xcc\x9c\xf1v\x02\x00\x00\x00t\x14\xf2v\xd0\x1d\xf2v\x01\x00\x00\x00\x04\x00\x00\x00\x1c\x00\x00\x00\x15\x00\x00\x01\x0c\xf5\xf8'/dev/bus/usb/001/004\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
What is the difference in reading from the named pipe between these two programs?
C recognises \x00 (the NUL character) as the end of a string (see: c-string), but Python does not. The garbage was always there in the FIFO, so your C-based writer is sending garbage to the FIFO for some reason (which we will never know because you haven't posted that code).

Non-blocking read on subprocess output without flush() and new line

I have a program that I can't modify. This program print data to stdout WITHOUT flushing it or put \n inside and wait for input and so on.
My question is how can I, from a Python script, print in real-time stdout and write into his stdin? I found some ways to write into his stdin without closing the programs but the problem remains for printing his stdout too.
In fact, there are some issues with thread, Popen and fcntl to print in real time his output but they all assumes that the program flush stdout after each print and include \n in their output.
To be clear, let's say I have a program test.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void)
{
char name[100], age[100], location[100];
fprintf (stdout, "\nWhat is your name : ");
fgets (name, sizeof (name), stdin);
name[strcspn (name, "\n")] = '\0';
fprintf (stdout, "How old are you : ");
fgets (age, sizeof (age), stdin);
age[strcspn (age, "\n")] = '\0';
fprintf (stdout, "Where do you live : ");
fgets (location, sizeof (location), stdin);
location[strcspn (location, "\n")] = '\0';
fprintf (stdout, "\nHello %s, you have %s years old and live in
%s\n\n", name, age, location);
return 0;
}
How can I, from a Python script, output the first fprintf() then writing answer into his stdin and so on in the same way I could simply launch test.c?
The purpose is to control data sent to this program from a script and still having return on what happens.
You may use the following program which is heavily relying on the subprocess package from the standard Python language:
def run_program(cmd, sinput=''):
"""Run the command line and output (ret, sout, serr)."""
import subprocess
proc = subprocess.Popen(cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
sin = proc.stdin
sout, serr = proc.communicate(sinput.encode("utf-8"))
ret = proc.wait()
return (ret, sout, serr)
So, the program you just wrote in C would give the following:
cmd = ['myprogram']
sinput = 'myname\n6\nWhitechapel\n'
(ret, sout, serr) = run_program(cmd, sinput)
Note that you cannot avoid the \n character simply because it is used by your target program to know that you send the answer to a question.

How is Python blocking signals while os.system("sleep...")?

When I run this Python script with os.system on Ubuntu 12.04:
import os, signal
signal.signal(signal.SIGABRT, lambda *args: os.write(2, 'HANDLER\n'))
print 'status=%r' % os.system('sleep 5')
, and then I send SIGABRT to the script process many times within 5 seconds, I get the following output:
status=0
HANDLER
This indicates that the signal delivery was blocked until sleep 5 exited, and then only a single signal was delivered.
However, with subprocess.call:
import os, signal, subprocess
signal.signal(signal.SIGABRT, lambda *args: os.write(2, 'HANDLER\n'))
print 'cstatus=%r' % subprocess.call('sleep 5', shell=True)
, all individual signals are delivered early:
HANDLER
HANDLER
HANDLER
cstatus=0
To distinguish the magic in glibc from the magic in Python, I rewrote the Python script in C, so os.system became system(3):
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void handler(int signum) { (void)signum; write(2, "HANDLER\n", 8); }
int main(int argc, char **argv) {
int got;
struct sigaction sa;
(void)argc; (void)argv;
memset(&sa, 0, sizeof sa);
sa.sa_handler = handler;
if (0 != sigaction(SIGABRT, &sa, NULL)) return 3;
got = system("sleep 5");
return !printf("system=0x%x\n", got);
}
Signals got delivered early:
HANDLER
HANDLER
HANDLER
system=0x0
So I inferred that the magic is in Python 2.7, not in eglibc. But where is the magic? Based on the strace output and looking at the posix_system function in Modules/posixmodule.c, I couldn't figure out how Python blocks the signal until os.system returns.
Relevant code from Modules/posixmodule.c:
static PyObject *posix_system(PyObject *self, PyObject *args) {
char *command;
long sts;
if (!PyArg_ParseTuple(args, "s:system", &command)) return NULL;
Py_BEGIN_ALLOW_THREADS
sts = system(command);
Py_END_ALLOW_THREADS
return PyInt_FromLong(sts);
}
Maybe the magic is in Py_BEGIN_ALLOW_THREADS?
Do I understand correctly that it's impossible for my Python signal handler (set up by signal.signal) to execute until os.system returns?
Is it because signal handlers are blocked (on the Python level, not on the OS level) until Py_END_ALLOW_THREADS returns?
Here is the strace output of the Python code with os.system: http://pastebin.com/Wjn9KBye
Maybe the magic is in PY_BEGIN_ALLOW_THREADS?
The magic is mostly in system itself. system cannot return EINTR, so the libc implementation goes to pains to resume its wait'ing on the child process. That means in your use of os.system, control never returns to python until the underlying system completes, and thus the python signal handling mechanics aren't invoked timely.
subprocess.call, however, is essentially doing this:
# Compare subprocess.py:Popen/_eintr_retry_call(os.waitpid, self.pid, 0)
while True:
try:
return os.waitpid(the_child_pid, 0)
except OSError, e:
if e.errno == errno.EINTR: # signal.signal() handler already invoked
continue
raise
Here control does return to python when the underlying wait is interrupted. The OSError/EINTR prompts python to see if any signals were tripped and, if so, to invoke the user-supplied code block associated with that signal. (And that's how the interpreter adapts the system's signal semantics: set a flag, and check it between "atomic" python operations, invoking the user's code if appropriate.)

Categories

Resources