Bad implementation of mkostemp in uClibc

Anthony G. Basile basile at opensource.dyc.edu
Sun Sep 28 15:18:07 UTC 2014


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


More information about the uClibc mailing list