Asblarf
Asblarf

Reputation: 491

How to check whether a buffer is writable?

I am writing a shared library that overrides some syscalls. Among them is the read(int fd, void *buf, size_t count) syscall. This library is, of course, in User Space.

So, in my library, I'm catching the read() call from the application (which uses LD_PRELOAD to preload my lib), do a bunch of things and, at some point, write data to the application buffer (void *buf).

Is there a way for me to check whether the whole application buffer is writable?

Most of the time it is not an issue but I've come across applications that were so poorly written that they would post read-only buffer in their read() call, leading to a segfault in my code when I'm performing a memcpy() with their buffer as destination, which makes sense, of course.

Note 1: I'm currently having a look at how the Kernel is handling that situation in the actual sys_read() in fs/read_write.c but it's not that trivial to understand.

Note 2: The solution should add as little overhead as possible.

Upvotes: 0

Views: 310

Answers (2)

Arun Taylor
Arun Taylor

Reputation: 1572

This is a tweak of @R. response to mitigate performance hit.

It is not necessary to keep opening and closing /dev/zero. Just open it once and leave it open. Then, every time you are attempting to do a read, just read one byte to find out if the buffer is writable.

#include <sys/types.h>
#include <sys/fcntl.h>
#include <unistd.h>   

int                
check_writable(char *buf)
{                         
    static int fd;
    int r;

    if (fd == 0) {
            fd = open("/dev/zero", O_RDONLY);
    }

    r = read(fd, buf, 1);

    if (r != 1) {
            return(0);
    }

    return(1);
}             


int
main()
{  
    char *s, wr[8], *rd = "read-only buf";
    int j, r;

    for (j = 0; j < 2; j++) {
        if (j == 0) {
            s = rd;
        }
        else {
            s = wr;
        }

        r = check_writable(s);
        if (r == 0) {
            printf("read-only buffer\n");
        }
        else {
            printf("writable buffer\n");
        }
    }
}

Upvotes: 0

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215193

Try this:

int fd = open("/dev/zero", O_RDONLY);
ssize_t ret = read(fd, dest, amt_to_write);
int err = errno;
close(fd);
if (ret<0 && err==EFAULT) ...

Upvotes: 1

Related Questions