-3

There is a process (not process that I wrote) in Arm Linux that write the stdout for /dev/console that unaccessible to me.

How can I redirect that stdout to file ,so I can watch this process output?

Of course I have root on this Arm Linux and I can compile code .

  • thousand and one solutions - almost all of which are dependent on the **kernel version**, **the operating system version if any**, **kernel compilation settings etc**... yet you do not mention any. I've successfully used ptrace with seccomp just quite recentlly, so it can be used but it is not by far the simplest solution and I would prefer any other if I would get it to work in *my* use case. – Antti Haapala -- Слава Україні Jul 15 '20 at 04:11

1 Answers1

0

I would write a minimal dynamic library that interposes open(), handling open("/dev/console", ...) separately. Then, run the other binary with LD_PRELOAD environment variable set to point to that library.

At minimum, something like the following libnoconsole.c should work:

#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <unistd.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <errno.h>

#ifndef   OLD_PATH
#define   OLD_PATH  "/dev/console"
#endif
#ifndef   NEW_PATH
#define   NEW_PATH  "/tmp/log"
#endif

static int (*original_open)(const char *, int, ...) = NULL;
static int (*original_openat)(int, const char *, int, ...) = NULL;

static int match(const char *a, const char *b)
{
    while (*a == *b)
        if (!*a) {
            return 1;
        } else {
            a++;
            b++;
        }
    return 0;
}

int open(const char *pathname, int flags, ...)
{
    if (!original_open)
        original_open = dlsym(RTLD_NEXT, "open");

    if (!original_open) {
        errno = ENOSYS;
        return -1;
    }

    if (match(pathname, OLD_PATH))
        return original_open(NEW_PATH, O_RDWR | O_CREAT, 0600);

    if (flags & (O_CREAT | O_TMPFILE)) {
        va_list  args;
        mode_t   mode;

        va_start(args, flags);
        mode = va_arg(args, mode_t);
        va_end(args);

        return original_open(pathname, flags, mode);
    } else
        return original_open(pathname, flags);
}

int openat(int dirfd, const char *pathname, int flags, ...)
{
    if (!original_openat)
        original_openat = dlsym(RTLD_NEXT, "openat");

    if (!original_openat) {
        errno = ENOSYS;
        return -1;
    }

    if (match(pathname, OLD_PATH))
        return original_openat(AT_FDCWD, NEW_PATH, O_RDWR | O_CREAT, 0600);

    if (flags & (O_CREAT | O_TMPFILE)) {
        va_list  args;
        mode_t   mode;

        va_start(args, flags);
        mode = va_arg(args, mode_t);
        va_end(args);

        return original_openat(dirfd, pathname, flags, mode);
    } else
        return original_openat(dirfd, pathname, flags);
}

Compile it using

gcc -Wall -O2 -c libnoconsole.c

gcc -Wall -O2 -shared -Wl,-soname,libnoconsole.so libnoconsole.o -ldl -o libnoconsole.so

and run your program via

env LD_PRELOAD=$PWD/libnoconsole.so the-other-program

and it should save its output to /tmp/log instead of /dev/console.

The reason for above using the silly match() instead of !strcmp() is that strcmp() wasn't always an async-signal safe function, whereas open() and openat() are: it's a small wart to avoid potential issues.

None
  • 281
  • 1
  • 3