[klibc] klibc 1.5.21-1 and mksh

Thorsten Glaser tg at mirbsd.de
Fri Jan 28 05:23:40 PST 2011


tags 516774 = patch
tags 516294 = upstream
thanks

Hi!

Please find attached a diff closing #516774 by adding mkstemp(3),
again with a minimalistic pseudo-arc4random(3) behind it. I’ve
revisited the code. An mkstemp testsuite from the ’net shows it
works, except for not caring how many ‘X’en are in the template.

Addressing #516294, it allows compiling and linking an mksh from
today’s CVS against it:
tg at tg-sidvm:~/b $ CPPFLAGS=-DMKSH_NO_LIMITS CC=klcc dash ../mksh/Build.sh -r

However, the signal problem persists:

tg at tg-sidvm:~/b $ ./mksh -c 'print hi'
hi
tg at tg-sidvm:~/b $ ./mksh -c 'ls'
Rebuild.sh  eval.o  expr.o   histrap.o  lalloc.o  main.o  mksh   signames.inc  test.sh  var.o
edit.o      exec.o  funcs.o  jobs.o     lex.o     misc.o  shf.o  syn.o         tree.o
^C^\
130|tg at tg-sidvm:~/b $

This basically means: builtins can run fine, external programmes
never return (Haiku used to have the same problem, they fixed a
signal delivery related kernel bug of theirs to solve it; Syllable
Desktop and Plan 9 still have this problem).

Some more details (add -g to Build.sh to get a debugging executable):

GNU gdb (GDB) 7.2-debian
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/tg/b/mksh...done.
Attaching to program: /home/tg/b/mksh, process 18642
0x08072b76 in __syscall_common ()
(gdb) bt
#0  0x08072b76 in __syscall_common ()
#1  0x00000048 in ?? ()
#2  0x08060aac in j_waitj (j=0x0, flags=<value optimized out>, where=0x413 <Address 0x413 out of bounds>)
    at ../mksh/jobs.c:987
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) info r
eax            0xfffffdfe       -514
ecx            0x413    1043
edx            0x8075b17        134699799
ebx            0x807dd48        134733128
esp            0xbfcf9618       0xbfcf9618
ebp            0xbfcf9688       0xbfcf9688
esi            0xbfcf9650       -1076914608
edi            0xb770e0e4       -1217339164
eip            0x8072b76        0x8072b76 <__syscall_common+26>
eflags         0x246    [ PF ZF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0

The part of the source:

    987                 sigsuspend(&sm_default);

As I already stated, an 1.5.15 patched with C99, getrusage,
arc4random and mkstemp used to work, so a regression was
introduced later. (I had hoped for 1.5.21 to work, as maks’
blog posting said something about signal fixes.) However,
I can no longer get one of the older klibc to build on a
newer Debian unstable due to kernel headers related changes,
so bisecting is almost impossible (for me, that is).

I would greatly appreciate if someone could look at the
second issue and, addressing the first, accept the patch
adding mkstemp() as a feature.

Thanks in advance,
//mirabilos
-- 
15:41⎜<Lo-lan-do:#fusionforge> Somebody write a testsuite for helloworld :-)
-------------- next part --------------
diff -Nru klibc-1.5.21/debian/changelog klibc-1.5.21/debian/changelog
--- klibc-1.5.21/debian/changelog	2011-01-25 22:47:03.000000000 +0000
+++ klibc-1.5.21/debian/changelog	2011-01-28 12:59:52.000000000 +0000
@@ -1,3 +1,12 @@
+klibc (1.5.21-1+tg.1) unstable; urgency=low
+
+  * debian/patches/add-{arc4random,mkstemp}: add a minimalistic
+    implementation of the arc4random() API on top of jrand48(3)
+    to have a self-seeding PRNG; add simple mkstemp(3) implemen-
+    tation using it. (Closes: #516774)
+
+ -- Thorsten Glaser <tg at mirbsd.de>  Fri, 28 Jan 2011 12:59:06 +0000
+
 klibc (1.5.21-1) unstable; urgency=low
 
   * New upstream release (i386 signal(), make 3.82, cleanups)
diff -Nru klibc-1.5.21/debian/patches/add-arc4random klibc-1.5.21/debian/patches/add-arc4random
--- klibc-1.5.21/debian/patches/add-arc4random	1970-01-01 00:00:00.000000000 +0000
+++ klibc-1.5.21/debian/patches/add-arc4random	2011-01-28 12:54:21.000000000 +0000
@@ -0,0 +1,206 @@
+* Include a helper function needed by add-mkstemp
+  implementing a minimal arc4random(3) API on top
+  of jrand48; self-seeding when /proc is mounted.
+
+  Entropy sources:
+  - 36 bytes from /proc/sys/kernel/random/uuid
+  - position of temp. buffer on stack (randomised on recent kernels)
+
+  Additional variation (non-random) via:
+  - PID of last stir call
+  - PID of current stir call
+  - count of arc4random() calls since last stir
+  - time of current stir call
+  - size of user-provided data
+  - position of arc4random_addrandom() argument on stack
+  - filedescriptor of /proc/sys/kernel/random/uuid
+  - count of bytes read from /proc/sys/kernel/random/uuid
+
+  After stirring, it's good for 65535 arc4random() calls.
+  The first call to arc4random() after fork() re-stirs.
+
+Index: klibc-1.5.21/usr/include/stdlib.h
+===================================================================
+--- klibc-1.5.21.orig/usr/include/stdlib.h	2011-01-28 12:00:27.000000000 +0000
++++ klibc-1.5.21/usr/include/stdlib.h	2011-01-28 12:00:36.000000000 +0000
+@@ -8,6 +8,7 @@
+ #include <klibc/extern.h>
+ #include <klibc/compiler.h>
+ #include <stddef.h>
++#include <bitsize/stdint.h>
+ 
+ #include <malloc.h>
+ 
+@@ -61,6 +62,11 @@
+ __extern unsigned short *seed48(const unsigned short *);
+ __extern void srand48(long);
+ 
++/* arc4random API emulation on top of jrand48 algorithm */
++__extern uint32_t arc4random(void);
++__extern void arc4random_stir(void);
++__extern void arc4random_addrandom(unsigned char *, int);
++
+ #define RAND_MAX 0x7fffffff
+ static __inline__ int rand(void)
+ {
+Index: klibc-1.5.21/usr/klibc/Kbuild
+===================================================================
+--- klibc-1.5.21.orig/usr/klibc/Kbuild	2011-01-28 12:00:27.000000000 +0000
++++ klibc-1.5.21/usr/klibc/Kbuild	2011-01-28 12:01:27.000000000 +0000
+@@ -47,6 +47,7 @@
+ 	  time.o utime.o llseek.o nice.o getpriority.o \
+ 	  qsort.o bsearch.o \
+ 	  lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \
++	  arc4random.o \
+ 	  inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \
+ 	  inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \
+ 	  send.o recv.o \
+Index: klibc-1.5.21/usr/klibc/arc4random.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ klibc-1.5.21/usr/klibc/arc4random.c	2011-01-28 12:35:21.000000000 +0000
+@@ -0,0 +1,144 @@
++/*-
++ * Minimum self-seeding PRNG/SRNG implementation, exposed
++ * via the standard BSD arc4random(3) API, for klibc
++ *
++ * Copyright (c) 2009, 2011
++ *	Thorsten Glaser <tg at mirbsd.de>
++ *
++ * This file is available under the same terms ("historic
++ * permission clause") as klibc itself or under the terms
++ * of The MirOS Licence (dual licenced).
++ */
++
++#include <sys/types.h>
++#include <sys/time.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++static struct arc4random_state {
++	unsigned short seed[3];		/* for jrand48 */
++	unsigned short cnt;		/* invocation count */
++	pid_t proc;			/* PID of last seed */
++} arc4_state = { { 0, 0, 0 }, 0, 0 };
++
++static void arc4_stir(pid_t);
++
++/* Jenkins one-at-a-time hash */
++#define OAAT_Update(h, buf, siz) do {		\
++	register const uint8_t *OAATcp;		\
++	register int OAATn = (siz);		\
++						\
++	OAATcp = (const void *)(buf);		\
++	while (OAATn--) {			\
++		(h) += *OAATcp++;		\
++		(h) += (h) << 10;		\
++		(h) ^= (h) >> 6;		\
++	}					\
++} while (/* CONSTCOND */ 0)
++#define OAAT_Final(h) do {			\
++	(h) += (h) << 3;			\
++	(h) ^= (h) >> 11;			\
++	(h) += (h) << 15;			\
++} while (/* CONSTCOND */ 0)
++
++void
++arc4random_addrandom(unsigned char *dat, int datlen)
++{
++	register uint32_t h;
++	struct {
++		struct timeval tv;	/* brings variety if not entropy */
++		const void *sp;		/* stack is randomised by kernel */
++		uint32_t v;		/* datlen on first pass */
++	} additional_data;
++
++	gettimeofday(&additional_data.tv, NULL);
++	additional_data.sp = &additional_data;
++	additional_data.v = (uint32_t)datlen;
++
++	h = 0x100;			/* ideal start value for OAAT */
++	/* hash over additional data which introduces variety */
++	OAAT_Update(h, &additional_data, sizeof(additional_data));
++	/* and the data passed */
++	OAAT_Update(h, dat, datlen);
++	/* and the old state (including PID) */
++	OAAT_Update(h, &arc4_state, sizeof(arc4_state));
++	/* reassign part of additional_data for more variety */
++	additional_data.sp = dat;	/* argument address also varies */
++	additional_data.v = h;		/* keep some of h (dat, old state) */
++
++	/* split the hash into the new seed (first pass) */
++	OAAT_Final(h);
++	arc4_state.seed[1] = (unsigned short)(h & 0xFFFF);
++	arc4_state.seed[2] = (unsigned short)(h >> 16);
++
++	/* split half a hash of new additional_data into the new seed */
++	h = 0x100;
++	OAAT_Update(h, &additional_data, sizeof(additional_data));
++	OAAT_Final(h);
++	arc4_state.seed[0] = (unsigned short)(h & 0xFFFF);
++}
++
++static void
++arc4_stir(pid_t ourpid)
++{
++	/* define a "stir buffer" */
++#define UUID_LEN	36
++	struct {
++		union {
++			ssize_t numb;
++			pid_t newpid;
++		} u;
++		int fd;
++		int count;
++		char uuid[UUID_LEN];
++	} s;
++
++	if ((s.fd = open("/proc/sys/kernel/random/uuid", O_RDONLY)) != -1) {
++		s.count = 0;
++		while (s.count < UUID_LEN) {
++			s.u.numb = read(s.fd, s.uuid + s.count,
++			    UUID_LEN - s.count);
++			if (s.u.numb == -1) {
++				if (errno == EINTR) {
++					errno = 0;
++					continue;
++				}
++				break;
++			} else if (s.u.numb == 0)
++				break;
++			s.count += s.u.numb;
++		}
++		close(s.fd);
++	}
++	/* else, we are desperate and just use the stack content */
++#undef UUID_LEN
++
++	/* s.u.newpid != arc4_state.proc directly after fork(2) */
++	s.u.newpid = ourpid;
++
++	/* hash the stir buffer into the PRNG state */
++	arc4random_addrandom((unsigned char *)&s, sizeof(s));
++
++	/* ready to be used for a while */
++	arc4_state.proc = ourpid;
++	arc4_state.cnt = 0xFFFF;
++}
++
++void
++arc4random_stir(void)
++{
++	arc4_stir(getpid());
++}
++
++uint32_t
++arc4random(void)
++{
++	pid_t ourpid;
++
++	if (arc4_state.proc != (ourpid = getpid()) || arc4_state.cnt-- == 0)
++		arc4_stir(ourpid);
++	return ((uint32_t)(jrand48(arc4_state.seed) & 0xFFFFFFFF));
++}
diff -Nru klibc-1.5.21/debian/patches/add-mkstemp klibc-1.5.21/debian/patches/add-mkstemp
--- klibc-1.5.21/debian/patches/add-mkstemp	1970-01-01 00:00:00.000000000 +0000
+++ klibc-1.5.21/debian/patches/add-mkstemp	2011-01-28 12:54:52.000000000 +0000
@@ -0,0 +1,110 @@
+* Address #516774 by adding a relatively minimal mkstemp(3) implementation.
+  Requires add-arc4random to be applied first.
+
+Index: klibc-1.5.21/usr/include/stdlib.h
+===================================================================
+--- klibc-1.5.21.orig/usr/include/stdlib.h	2011-01-28 12:37:06.000000000 +0000
++++ klibc-1.5.21/usr/include/stdlib.h	2011-01-28 12:37:20.000000000 +0000
+@@ -85,6 +85,8 @@
+ 	srand48(__s);
+ }
+ 
++__extern int mkstemp(char *);
++
+ /* Basic PTY functions.  These only work if devpts is mounted! */
+ 
+ __extern int unlockpt(int);
+Index: klibc-1.5.21/usr/klibc/Kbuild
+===================================================================
+--- klibc-1.5.21.orig/usr/klibc/Kbuild	2011-01-28 12:37:06.000000000 +0000
++++ klibc-1.5.21/usr/klibc/Kbuild	2011-01-28 12:37:39.000000000 +0000
+@@ -47,7 +47,7 @@
+ 	  time.o utime.o llseek.o nice.o getpriority.o \
+ 	  qsort.o bsearch.o \
+ 	  lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \
+-	  arc4random.o \
++	  arc4random.o mkstemp.o \
+ 	  inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \
+ 	  inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \
+ 	  send.o recv.o \
+Index: klibc-1.5.21/usr/klibc/mkstemp.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ klibc-1.5.21/usr/klibc/mkstemp.c	2011-01-28 12:48:37.000000000 +0000
+@@ -0,0 +1,76 @@
++/*-
++ * Compact mkstemp(3)-only implementation, for klibc
++ *
++ * Copyright (c) 2009, 2011
++ *	Thorsten Glaser <tg at mirbsd.de>
++ *
++ * This file is available under the same terms ("historic
++ * permission clause") as klibc itself or under the terms
++ * of The MirOS Licence (dual licenced).
++ */
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++int
++mkstemp(char *template)
++{
++	int i;
++	char *cp, *sp;
++	struct stat sbuf;
++
++	cp = template;
++	while (*cp)
++		++cp;
++
++	sp = cp;
++	/* generate random suffix */
++	while (sp > template && sp[-1] == 'X') {
++		i = arc4random() % (26 + 26);
++		*--sp = i < 26 ? 'A' + i : 'a' + i - 26;
++	}
++	if (sp == cp) {
++		/* zero-length template or no X at its end */
++		errno = EINVAL;
++		return (-1);
++	}
++
++	/* check the target directory */
++	cp = sp;
++	while (cp > template && *cp != '/')
++		--cp;
++	if (cp > template) {
++		*cp = '\0';
++		i = stat(template, &sbuf);
++		*cp = '/';
++
++		if (i != 0)
++			/* stat failed, pass errno */
++			return (-1);
++		if (!S_ISDIR(sbuf.st_mode)) {
++			errno = ENOTDIR;
++			return (-1);
++		}
++	}
++
++	while (1) {
++		if ((i = open(template, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0 ||
++		    errno != EEXIST)
++			break;
++
++		while (*cp == 'Z')
++			if (!*++cp)
++				return (-1);
++		if (*cp == 'z')
++			*cp = 'A';
++		else
++			++*cp;
++	}
++	return (i);
++}
diff -Nru klibc-1.5.21/debian/patches/series klibc-1.5.21/debian/patches/series
--- klibc-1.5.21/debian/patches/series	2011-01-25 22:50:06.000000000 +0000
+++ klibc-1.5.21/debian/patches/series	2011-01-28 12:36:52.000000000 +0000
@@ -2,3 +2,5 @@
 klibc-linux-libc-dev
 insmod
 debian-changes-1.5.21-1
+add-arc4random
+add-mkstemp


More information about the klibc mailing list