Hi everyone,

While looking at musl's implementation of mkostemp [1] I found a serious problem in uClibc's implementation. In uClibc, libc/stdlib/mkostemp.c calls __gen_tempname in libc/misc/internals/tempname.c with kind = __GT_FILE and opens the file with

     fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);

thus completely ignoring the O_APPEND, O_CLOEXEC, and O_*SYNC flags [2]. In fact, it seems to confuse the file mode with the flags. This defeats the purpose of mkostemp, especially in the case of O_CLOEXEC which can be done with a followup call to fcntl, but at the loss of atomicity (and portibility because people expect it to just work).

I'm going to try to this up using ref [3] as the standard. (Thanks Rich Felker.)

I've written some POC to demonstrate the problem. Here are the results on glibc, musl and uClibc.

---- glibc --------

cc -o stealfd stealfd.c
cc -D_CLOEXEC -o test-cloexec test.c
cc -U_CLOEXEC -o test-nocloexec test.c

./test-cloexec
Bad file descriptor
Child exited with status 0
abc.UEOGER contains string ''

./test-nocloexec
Child exited with status 0
abc.e7syCR contains string 'test'

ls -al abc.*
-rw------- 1 root root 5 Sep 28 11:09 abc.e7syCR
-rw------- 1 root root 0 Sep 28 11:09 abc.UEOGER

-------------------


---- musl ---------

cc -o stealfd stealfd.c
cc -D_CLOEXEC -o test-cloexec test.c
cc -U_CLOEXEC -o test-nocloexec test.c

./test-cloexec
Bad file descriptor
Child exited with status 0
abc.DfOfhD contains string ''

./test-nocloexec
Child exited with status 0
abc.BfckJO contains string 'test'

ls -al abc.*
-rw------- 1 root root 5 Sep 28 15:06 abc.BfckJO
-rw------- 1 root root 0 Sep 28 15:06 abc.DfOfhD

-------------------

---- uCliblc ------

cc -o stealfd stealfd.c
cc -D_CLOEXEC -o test-cloexec test.c
cc -U_CLOEXEC -o test-nocloexec test.c

./test-cloexec
Child exited with status 0
abc.v741kr contains string 'test'

./test-nocloexec
Child exited with status 0
abc.Qc6iGz contains string 'test'

ls -al abc.*
---------- 1 root root 5 Sep 28 15:10 abc.Qc6iGz
---------- 1 root root 5 Sep 28 15:10 abc.v741kr

------------------


I've inlined the POC for easier reading. To obtain the above results, just do `make`.

---- Makefile -----

all: stealfd test-cloexec test-nocloexec
        @echo
        ./test-cloexec
        @echo
        ./test-nocloexec
        @echo
        ls -al abc.*
        @rm -f abc.*

stealfd: stealfd.c
        $(CC) -o $@ $^

test-cloexec: test.c
        $(CC) -D_CLOEXEC -o $@ $^

test-nocloexec: test.c
        $(CC) -U_CLOEXEC -o $@ $^

.PHONY: clean
clean:
        rm -f stealfd test-cloexec test-nocloexec abc.*

-------------------

---- test.c -------

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>

int main() {
        int fd, status;
        char buff[6];
        char template[] = "abc.XXXXXX";

#ifdef _CLOEXEC
        fd = mkostemp(template, O_CLOEXEC);
#else
        fd = mkostemp(template, 0);
#endif

        snprintf(buff, 6, "%d", fd);

        if(!fork()) execl("./stealfd", "stealfd", buff, NULL);

        wait(&status);
        printf("Child exited with status %d\n", WEXITSTATUS(status));

        memset(buff, 0, 6);
        lseek(fd, 0, SEEK_SET);
        errno = 0;
        if(read(fd, buff, 6) == -1) {
                printf("%s\n", strerror(errno));
                exit(EXIT_FAILURE);
        }
        printf("%s contains string '%s'\n", template, buff);

        close(fd);
        exit(EXIT_SUCCESS);
}

-------------------

---- stealfd.c ----

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[]) {
        int fd;

        if(argc < 2) {
                printf("Usage %s fd\n", argv[0]);
                exit(EXIT_FAILURE);
        }

        sscanf(argv[1], "%d", &fd);

        errno = 0;
        if(write(fd, "test\0", 5) == -1)
                printf("%s\n", strerror(errno));

        close(fd);
        exit(EXIT_SUCCESS);
}

-------------------


Ref.

[1] http://thread.gmane.org/gmane.linux.lib.musl.general/6199
[2] See mkstemp(3)
[3] http://austingroupbugs.net/view.php?id=411

--
Anthony G. Basile, Ph. D.
Chair of Information Technology
D'Youville College
Buffalo, NY 14201
(716) 829-8197
_______________________________________________
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Reply via email to