[klibc] mksh on klibc

Thorsten Glaser tg at mirbsd.de
Sun May 2 07:23:39 PDT 2010


Hi again,

I’ve attached a git patch series against maks’ repository (the
8d38b56e6f2c9dac342df3de919775cc38eba603 commit is a requirement
as well) to allow mksh to build against klibc.

There’s still one issue open with regards to signal handling,
which I mailed in private to maks in the hope of getting an
idea what went wrong (regression between 1.5.15-1 in Debian,
with the exact same four patches (above mentioned commit plus
the three attached) applied, and 1.5.18-1 in Debian with the
four patches applied).

Oh well, at least, with this patch series, it compiles… of
course, if you favour a different mkstemp() implementation
or would rather like the less preferable tempnam(), feel
free to do so. The stdio.h diff is required, though.

bye,
//mirabilos
-- 
FWIW, I'm quite impressed with mksh interactively. I thought it was much
*much* more bare bones. But it turns out it beats the living hell out of
ksh93 in that respect. I'd even consider it for my daily use if I hadn't
wasted half my life on my zsh setup. :-) -- Frank Terbeck in #!/bin/mksh
-------------- next part --------------
From a4f243c04e1c01514dc5f76abf66591fa47f6dae Mon Sep 17 00:00:00 2001
From: Thorsten Glaser <tg at mirbsd.org>
Date: Sun, 2 May 2010 14:15:48 +0000
Subject: [PATCH 1/3] Fix inlines to adhere to ISO C99.


Signed-off-by: Thorsten Glaser <tg at mirbsd.org>
---
 usr/include/stdio.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/usr/include/stdio.h b/usr/include/stdio.h
index 7d2c86d..14f85b2 100644
--- a/usr/include/stdio.h
+++ b/usr/include/stdio.h
@@ -85,12 +85,12 @@ __extern size_t _fread(void *, size_t, FILE *);
 __extern size_t _fwrite(const void *, size_t, FILE *);
 
 #ifndef __NO_FREAD_FWRITE_INLINES
-extern __inline__ size_t fread(void *__p, size_t __s, size_t __n, FILE * __f)
+static __inline__ size_t fread(void *__p, size_t __s, size_t __n, FILE * __f)
 {
 	return _fread(__p, __s * __n, __f) / __s;
 }
 
-extern __inline__ size_t
+static __inline__ size_t
 fwrite(const void *__p, size_t __s, size_t __n, FILE * __f)
 {
 	return _fwrite(__p, __s * __n, __f) / __s;
-- 
1.6.3.1

-------------- next part --------------
From 49a29db29dc47d53fae302648e276705e0c9ff45 Mon Sep 17 00:00:00 2001
From: Thorsten Glaser <tg at mirbsd.org>
Date: Sun, 2 May 2010 14:16:29 +0000
Subject: [PATCH 2/3] Add minimalistic arc4random(3) implementation.

Include a helper function implementing a minimal arc4random(3) API
on top of jrand48(3) self-seeding as long as /proc is mounted. The
implementation also makes use of ASLR provided entropy.

Signed-off-by: Thorsten Glaser <tg at mirbsd.org>
---
 usr/include/stdlib.h   |    6 ++
 usr/klibc/Kbuild       |    1 +
 usr/klibc/arc4random.c |  134 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 141 insertions(+), 0 deletions(-)
 create mode 100644 usr/klibc/arc4random.c

diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h
index 406f446..28c7150 100644
--- a/usr/include/stdlib.h
+++ b/usr/include/stdlib.h
@@ -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 long lrand48(void);
 __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)
 {
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index ab5212b..3812b78 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -47,6 +47,7 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \
 	  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 \
diff --git a/usr/klibc/arc4random.c b/usr/klibc/arc4random.c
new file mode 100644
index 0000000..27b1b3b
--- /dev/null
+++ b/usr/klibc/arc4random.c
@@ -0,0 +1,134 @@
+/*-
+ * Minimum self-seeding PRNG/SRNG implementation, exposed
+ * via the standard BSD arc4random(3) API, for klibc
+ *
+ * Copyright (c) 2009, 2010
+ *	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 {
+	pid_t proc;			/* PID of last seed */
+	unsigned short seed[3];		/* for jrand48 */
+	unsigned short cnt;		/* invocation count */
+} arc4_state = { 0, { 0, 0, 0 }, 0 };
+
+static void arc4_stir(pid_t);
+static uint32_t oaathash_update(register uint32_t,
+    register const unsigned char *, register int);
+
+/* Jenkins one-at-a-time hash */
+static uint32_t
+oaathash_update(register uint32_t h, register const unsigned char *cp,
+    register int n)
+{
+	while (n--) {
+		h += *cp++;
+		h += h << 10;
+		h ^= h >> 6;
+	}
+	return (h);
+}
+
+void
+arc4random_addrandom(unsigned char *dat, int datlen)
+{
+	register uint32_t h;
+
+	h = (uint32_t)jrand48(arc4_state.seed) & 0xFFFFFF00;
+
+	h = oaathash_update(h, (void *)&dat, sizeof(void *));
+	h = oaathash_update(h, (void *)&datlen, sizeof(int));
+	h = oaathash_update(h, dat, datlen);
+	h = oaathash_update(h, (unsigned char *)&arc4_state,
+	    (int)sizeof(arc4_state));
+	dat = (void *)&dat;
+	h = oaathash_update(h, (void *)&dat, sizeof(void *));
+	dat = (void *)&arc4_state;
+	h = oaathash_update(h, (void *)&dat, sizeof(void *));
+
+	/* oaathash_final */
+	h += h << 3;
+	h ^= h >> 11;
+	h += h << 15;
+
+	/* split the hash into the new seed */
+	arc4_state.seed[0] = 0x330E;
+	arc4_state.seed[1] = (unsigned short)(h & 0xFFFF);
+	arc4_state.seed[2] = (unsigned short)(h >> 16);
+}
+
+static void
+arc4_stir(pid_t ourpid)
+{
+#define UUID_LEN	36
+
+	struct {
+		struct timeval tv;
+		pid_t thepid;
+		int count;
+		int fd;
+		char uuid[UUID_LEN];
+	} stirbuf;
+
+	stirbuf.thepid = ourpid;
+	/* wish we had clock_gettime(2) for realtime AND monotonic */
+	gettimeofday(&stirbuf.tv, NULL);
+
+	if ((stirbuf.fd = open("/proc/sys/kernel/random/uuid",
+	    O_RDONLY)) != -1) {
+		stirbuf.count = 0;
+
+		while (stirbuf.count < UUID_LEN) {
+			ssize_t numb;
+
+			numb = read(stirbuf.fd, stirbuf.uuid + stirbuf.count,
+			    UUID_LEN - stirbuf.count);
+			if (numb == -1) {
+				if (errno == EINTR) {
+					errno = 0;
+					continue;
+				}
+				break;
+			} else if (numb == 0)
+				break;
+			stirbuf.count += numb;
+		}
+		close(stirbuf.fd);
+	}
+#undef UUID_LEN
+
+	/* we're desperate and just use what's there now */
+	arc4random_addrandom((unsigned char *)&stirbuf, sizeof(stirbuf));
+
+	/* 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);
+}
-- 
1.6.3.1

-------------- next part --------------
From fb83369f3bb5c16f9c30e2e757443baa28bdf3ad Mon Sep 17 00:00:00 2001
From: Thorsten Glaser <tg at mirbsd.org>
Date: Sun, 2 May 2010 14:17:05 +0000
Subject: [PATCH 3/3] Add a relatively minimal mkstemp(3) implementation.

This allows mksh to build against klibc (tempnam or, preferable,
mkstemp is required) and closes Debian #516774. The implementation
requires arc4random(3).

Signed-off-by: Thorsten Glaser <tg at mirbsd.org>
---
 usr/include/stdlib.h |    2 +
 usr/klibc/Kbuild     |    1 +
 usr/klibc/mkstemp.c  |   77 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+), 0 deletions(-)
 create mode 100644 usr/klibc/mkstemp.c

diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h
index 28c7150..74c9bf3 100644
--- a/usr/include/stdlib.h
+++ b/usr/include/stdlib.h
@@ -85,6 +85,8 @@ static __inline__ void srandom(unsigned int __s)
 	srand48(__s);
 }
 
+__extern int mkstemp(char *);
+
 /* Basic PTY functions.  These only work if devpts is mounted! */
 
 __extern int unlockpt(int);
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index 3812b78..085ffb1 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -56,6 +56,7 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \
 	  ctype/isgraph.o ctype/islower.o ctype/isprint.o \
 	  ctype/ispunct.o ctype/isspace.o ctype/isupper.o \
 	  ctype/isxdigit.o ctype/tolower.o ctype/toupper.o \
+	  mkstemp.o \
 	  userdb/getgrgid.o userdb/getgrnam.o userdb/getpwnam.o \
 	  userdb/getpwuid.o userdb/root_group.o userdb/root_user.o \
 	  setmntent.o endmntent.o getmntent.o
diff --git a/usr/klibc/mkstemp.c b/usr/klibc/mkstemp.c
new file mode 100644
index 0000000..eb128dc
--- /dev/null
+++ b/usr/klibc/mkstemp.c
@@ -0,0 +1,77 @@
+/*-
+ * Compact mkstemp(3)-only implementation, for klibc
+ *
+ * Copyright (c) 2009
+ *	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;
+	--cp;
+
+	if (cp < template) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	/* generate random suffix */
+	while (cp > template && *cp == 'X') {
+		i = arc4random() % (26 + 26);
+		*cp-- = i < 26 ? 'A' + i : 'a' + i - 26;
+	}
+	sp = cp + 1;
+
+	/* check the target directory */
+	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);
+		}
+	}
+
+	cp = sp;
+	for (;;) {
+		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);
+}
-- 
1.6.3.1



More information about the klibc mailing list