[klibc] [patches] klibc review unsorted patch queue

maximilian attems max at stro.at
Sat Mar 13 20:15:37 PST 2010


hello hpa,

please review this unsorted patch queue,
as I wasn't sure about them they didn't land yet in todays
pull request.

thanks
max

git clone git://git.debian.org/users/maks/klibc.git test

Thomas Bächler (1):
      klcc: compile shared by default

jeremy buisson (1):
      [klibc] sparc64: fix bad 32 bits socket syscalls

maximilian attems (1):
      [klibc] add losetup utils

the klcc one should be ok, the sparc patch looks like a wild hack
(need to test if it fixes the referenced sparc bug)
and the losetup may need refinments, tested it out, seems to work.
afaik the encrypted loops are deprecated due to security vuln..

git diff --stat  --summary master...test
 klcc/klcc.in             |    2 +-
 usr/klibc/SYSCALLS.def   |    5 +
 usr/klibc/socketcalls.pl |    2 +-
 usr/utils/Kbuild         |    4 +-
 usr/utils/loop.h         |   49 +++++
 usr/utils/losetup.c      |  481 ++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 540 insertions(+), 3 deletions(-)
 create mode 100644 usr/utils/loop.h
 create mode 100644 usr/utils/losetup.c


commit 4d0c11edfdad0493d97466b00e75b33786bab762
Author: jeremy buisson <jeremy.buisson at st-cyr.terre-net.defense.gouv.fr>
Date:   Wed May 27 08:57:23 2009 +0200

    [klibc] sparc64: fix bad 32 bits socket syscalls
    
    
    The 32 bits version of socket-related syscalls for sparc/sparc64 does
    not seem to conform to the interface provided by the kernel. As a
    result, klibc-utils commands such as ipconfig ends with a "ipconfig:
    eth0: socket(AF_INET): Function not implemented".
    
    See bug #444087 for the log with an older version. See for the following
    session for another evidence of the problem with a newer version:
    jeremy at sunny:~$ /usr/lib/klibc/bin/ipconfig lo
    ipconfig: lo: socket(AF_INET): Function not implemented
    /usr/lib/klibc/bin/ipconfig: no devices to configure
    
    Looking at the source code, it seems there is 2 call mechanisms:
    - if the kernel header files (asm/unistd.h) defines __NR_socket (and so
    on), the makefiles uses the syscall interface ;
    - otherwise, the makefiles uses the socketcall interface, which wraps
    the call into a common syscall (named socketcall).
    See the <src>/usr/klibc/syscalls.pl and <src>/usr/klibc/socketcalls.pl
    for details.
    
    Looking at the kernel source code for the 32 bits syscall table for the
    sparc64 architecture <src-2.6.26>/arch/sparc64/kernel/systbls.S, we see
    at index __NR_socket (97 according to asm-sparc/unistd.h and to
    asm-sparc64/unistd.h) that the entry points to sys_nis_syscall. Looking
    in <src-2.6.26>/arch/sparc64/kernel/syscalls.S, it branches to
    c_sys_nis_syscall, which (<src-2.6.26>/arch/sparc64/kernel/sys_sparc.c)
    returns ENOSYS, the error code for non-implemented syscalls.
    
    According to my quick tests, there are 2 workarounds:
    1) compile klibc to sparc64, as the 64 bits syscall table of the kernel
    provides the direct socket (and related) syscalls
    2) patch klibc such that it uses socketcall when targeting sparc(32).
    
    
    http://bugs.debian.org/444087
    
    Here is a sample patch for the 2nd option:

diff --git a/usr/klibc/SYSCALLS.def b/usr/klibc/SYSCALLS.def
index c12d525..0599dac 100644
--- a/usr/klibc/SYSCALLS.def
+++ b/usr/klibc/SYSCALLS.def
@@ -259,4 +259,9 @@ int sysinfo(struct sysinfo *);
  * system calls.
  */
 <?!i386> long socketcall::__socketcall(int, const unsigned long *);
+#if !defined(__sparc__) && !defined(__arch64__)
+/*
+ * SPARC does not have direct syscalls for socket
+ */
 #include "SOCKETCALLS.def"
+#endif
diff --git a/usr/klibc/socketcalls.pl b/usr/klibc/socketcalls.pl
index e6f75ab..01993e8 100644
--- a/usr/klibc/socketcalls.pl
+++ b/usr/klibc/socketcalls.pl
@@ -63,7 +63,7 @@ while ( defined($line = <FILE>) ) {
 
 	    print OUT "#include \"socketcommon.h\"\n";
 	    print OUT "\n";
-	    print OUT "#ifndef __NR_${name}\n\n";
+	    print OUT "#if (defined(__sparc__) && !defined(__arch64__)) || !defined __NR_${name}\n\n";
 
 	    print OUT "extern long __socketcall(int, const unsigned long *);\n\n";
 

commit 5390b6821d21a1469566e589727d36b97c1bd748
Author: maximilian attems <max at stro.at>
Date:   Sun Mar 14 04:44:29 2010 +0100

    [klibc] add losetup utils
    
    seen on the OpenEmbedded repository,
    added small cleanups, may need more..
    
    Cc: Andrea Adami <andrea.adami at gmail.com>
    Signed-off-by: maximilian attems <max at stro.at>

diff --git a/usr/utils/Kbuild b/usr/utils/Kbuild
index 354a364..57e2d08 100644
--- a/usr/utils/Kbuild
+++ b/usr/utils/Kbuild
@@ -3,7 +3,7 @@
 #
 
 progs := chroot dd mkdir mkfifo mknod mount pivot_root umount
-progs += true false sleep ln nuke minips cat ls
+progs += true false sleep ln nuke minips cat ls losetup
 progs += uname halt kill readlink cpio sync dmesg
 
 static-y := $(addprefix static/, $(progs))
@@ -56,6 +56,8 @@ static/cpio-y	    := cpio.o
 shared/cpio-y       := cpio.o
 static/sync-y       := sync.o
 shared/sync-y       := sync.o
+static/losetup-y    := losetup.o
+shared/losetup-y    := losetup.o
 
 # Additionally linked targets
 always := static/reboot static/poweroff shared/reboot shared/poweroff
diff --git a/usr/utils/loop.h b/usr/utils/loop.h
new file mode 100644
index 0000000..9839f57
--- /dev/null
+++ b/usr/utils/loop.h
@@ -0,0 +1,49 @@
+#define LO_CRYPT_NONE	0
+#define LO_CRYPT_XOR	1
+#define LO_CRYPT_DES	2
+#define LO_CRYPT_CRYPTOAPI 18
+
+#define LOOP_SET_FD		0x4C00
+#define LOOP_CLR_FD		0x4C01
+#define LOOP_SET_STATUS		0x4C02
+#define LOOP_GET_STATUS		0x4C03
+#define LOOP_SET_STATUS64	0x4C04
+#define LOOP_GET_STATUS64	0x4C05
+
+#define LO_NAME_SIZE	64
+#define LO_KEY_SIZE	32
+
+struct loop_info {
+	int		lo_number;
+	dev_t		lo_device;
+	unsigned long	lo_inode;
+	dev_t		lo_rdevice;
+	int		lo_offset;
+	int		lo_encrypt_type;
+	int		lo_encrypt_key_size;
+	int		lo_flags;
+	char		lo_name[LO_NAME_SIZE];
+	unsigned char	lo_encrypt_key[LO_KEY_SIZE];
+	unsigned long	lo_init[2];
+	char		reserved[4];
+};
+
+/*
+ * Where to get __u8, __u32, __u64? Let us use unsigned char/int/long long
+ * and get punished when someone comes with 128-bit long longs.
+ */
+struct loop_info64 {
+	unsigned long long	lo_device;
+	unsigned long long	lo_inode;
+	unsigned long long	lo_rdevice;
+	unsigned long long	lo_offset;
+	unsigned long long	lo_sizelimit; /* bytes, 0 == max available */
+	unsigned int		lo_number;
+	unsigned int		lo_encrypt_type;
+	unsigned int		lo_encrypt_key_size;
+	unsigned int		lo_flags;
+	unsigned char		lo_file_name[LO_NAME_SIZE];
+	unsigned char		lo_crypt_name[LO_NAME_SIZE];
+	unsigned char		lo_encrypt_key[LO_KEY_SIZE];
+	unsigned long long	lo_init[2];
+};
diff --git a/usr/utils/losetup.c b/usr/utils/losetup.c
new file mode 100644
index 0000000..e494183
--- /dev/null
+++ b/usr/utils/losetup.c
@@ -0,0 +1,481 @@
+/* Originally from Ted's losetup.c */
+
+#define LOOPMAJOR	7
+
+/*
+ * losetup.c - setup and control loop devices
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysmacros.h>
+#include <string.h>
+
+#include "loop.h"
+
+extern int verbose;
+extern char *progname;
+extern char *xstrdup (const char *s);	/* not: #include "sundries.h" */
+extern void error (const char *fmt, ...);	/* idem */
+
+/* caller guarantees n > 0 */
+void xstrncpy(char *dest, const char *src, size_t n)
+{
+	strncpy(dest, src, n-1);
+	dest[n-1] = 0;
+}
+
+
+static int loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info)
+{
+	memset(info, 0, sizeof(*info));
+	info->lo_number = info64->lo_number;
+	info->lo_device = info64->lo_device;
+	info->lo_inode = info64->lo_inode;
+	info->lo_rdevice = info64->lo_rdevice;
+	info->lo_offset = info64->lo_offset;
+	info->lo_encrypt_type = info64->lo_encrypt_type;
+	info->lo_encrypt_key_size = info64->lo_encrypt_key_size;
+	info->lo_flags = info64->lo_flags;
+	info->lo_init[0] = info64->lo_init[0];
+	info->lo_init[1] = info64->lo_init[1];
+	if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
+		memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
+	else
+		memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE);
+	memcpy(info->lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE);
+
+	/* error in case values were truncated */
+	if (info->lo_device != info64->lo_device ||
+			info->lo_rdevice != info64->lo_rdevice ||
+			info->lo_inode != info64->lo_inode ||
+			info->lo_offset != info64->lo_offset)
+		return -EOVERFLOW;
+
+	return 0;
+}
+
+
+static int show_loop(char *device)
+{
+	struct loop_info loopinfo;
+	struct loop_info64 loopinfo64;
+	int fd, errsv;
+
+	if ((fd = open(device, O_RDONLY)) < 0) {
+		int errsv = errno;
+		fprintf(stderr, "loop: can't open device %s: %s\n",
+			device, strerror (errsv));
+		return 2;
+	}
+
+	if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) {
+
+		loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*';
+		loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0;
+		loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0;
+
+		printf("%s: [%04llx]:%llu (%s)",
+		       device, loopinfo64.lo_device, loopinfo64.lo_inode,
+		       loopinfo64.lo_file_name);
+
+		if (loopinfo64.lo_offset)
+			printf(", offset %lld", loopinfo64.lo_offset);
+
+		if (loopinfo64.lo_sizelimit)
+			printf(", sizelimit %lld", loopinfo64.lo_sizelimit);
+
+		if (loopinfo64.lo_encrypt_type ||
+		    loopinfo64.lo_crypt_name[0]) {
+			char *e = loopinfo64.lo_crypt_name;
+
+			if (*e == 0 && loopinfo64.lo_encrypt_type == 1)
+				e = "XOR";
+			printf(", encryption %s (type %d)",
+			       e, loopinfo64.lo_encrypt_type);
+		}
+		printf("\n");
+		close (fd);
+		return 0;
+	}
+
+	if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0) {
+		printf ("%s: [%04x]:%ld (%s)",
+			device, loopinfo.lo_device, loopinfo.lo_inode,
+			loopinfo.lo_name);
+
+		if (loopinfo.lo_offset)
+			printf(", offset %d", loopinfo.lo_offset);
+
+		if (loopinfo.lo_encrypt_type)
+			printf(", encryption type %d\n",
+			       loopinfo.lo_encrypt_type);
+
+		printf("\n");
+		close (fd);
+		return 0;
+	}
+
+	errsv = errno;
+	fprintf(stderr, "loop: can't get info on device %s: %s\n",
+		device, strerror (errsv));
+	close (fd);
+	return 1;
+}
+
+int
+is_loop_device (const char *device) {
+	struct stat statbuf;
+
+	return (stat(device, &statbuf) == 0 &&
+		S_ISBLK(statbuf.st_mode) &&
+		major(statbuf.st_rdev) == LOOPMAJOR);
+}
+
+#define SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+char * find_unused_loop_device (void)
+{
+	/* Just creating a device, say in /tmp, is probably a bad idea -
+	   people might have problems with backup or so.
+	   So, we just try /dev/loop[0-7]. */
+	char dev[20];
+	char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
+	int i, j, fd, somedev = 0, someloop = 0, permission = 0;
+	struct stat statbuf;
+	struct loop_info loopinfo;
+
+	for (j = 0; j < SIZE(loop_formats); j++) {
+		for(i = 0; i < 256; i++) {
+			sprintf(dev, loop_formats[j], i);
+			if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
+				somedev++;
+				fd = open (dev, O_RDONLY);
+				if (fd >= 0) {
+					if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
+						someloop++;		/* in use */
+					else if (errno == ENXIO) {
+						close (fd);
+						return xstrdup(dev);/* probably free */
+					}
+					close (fd);
+				} else if (errno == EACCES)
+					permission++;
+
+				continue;/* continue trying as long as devices exist */
+			}
+			break;
+		}
+	}
+
+	if (!somedev)
+		error("%s: could not find any device /dev/loop#", progname);
+	else if (!someloop && permission)
+		error("%s: no permission to look at /dev/loop#", progname);
+	else if (!someloop)
+		error(
+		    "%s: Could not find any loop device. Maybe this kernel "
+		    "does not know\n"
+		    "       about the loop device? (If so, recompile or "
+		    "`modprobe loop'.)", progname);
+	else
+		error("%s: could not find any free loop device", progname);
+	return 0;
+}
+
+/*
+ * A function to read the passphrase either from the terminal or from
+ * an open file descriptor.
+ */
+static char * xgetpass(int pfd, const char *prompt)
+{
+	char *pass;
+	int buflen, i;
+
+	pass = NULL;
+	buflen = 0;
+	for (i=0; ; i++) {
+		if (i >= buflen-1) {
+				/* we're running out of space in the buffer.
+				 * Make it bigger: */
+			char *tmppass = pass;
+			buflen += 128;
+			pass = realloc(tmppass, buflen);
+			if (pass == NULL) {
+				/* realloc failed. Stop reading. */
+				error("Out of memory while reading passphrase");
+				pass = tmppass; /* the old buffer hasn't changed */
+				break;
+			}
+		}
+		if (read(pfd, pass+i, 1) != 1 ||
+		    pass[i] == '\n' || pass[i] == 0)
+			break;
+	}
+
+	if (pass == NULL)
+		return "";
+
+	pass[i] = 0;
+	return pass;
+}
+
+static int digits_only(const char *s)
+{
+	while (*s)
+		if (!isdigit(*s++))
+			return 0;
+	return 1;
+}
+
+int set_loop(const char *device, const char *file, unsigned long long offset,
+	 const char *encryption, int pfd, int *loopro) {
+	struct loop_info64 loopinfo64;
+	int fd, ffd, mode, i;
+	char *pass;
+
+	mode = (*loopro ? O_RDONLY : O_RDWR);
+	if ((ffd = open(file, mode)) < 0) {
+		if (!*loopro && errno == EROFS)
+			ffd = open(file, mode = O_RDONLY);
+		if (ffd < 0) {
+			perror(file);
+			return 1;
+		}
+	}
+	if ((fd = open(device, mode)) < 0) {
+		perror (device);
+		return 1;
+	}
+	*loopro = (mode == O_RDONLY);
+
+	memset(&loopinfo64, 0, sizeof(loopinfo64));
+
+	xstrncpy(loopinfo64.lo_file_name, file, LO_NAME_SIZE);
+
+	if (encryption && *encryption) {
+		if (digits_only(encryption)) {
+			loopinfo64.lo_encrypt_type = atoi(encryption);
+		} else {
+			loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
+			snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE,
+				 "%s", encryption);
+		}
+	}
+
+	loopinfo64.lo_offset = offset;
+
+
+	switch (loopinfo64.lo_encrypt_type) {
+	case LO_CRYPT_NONE:
+		loopinfo64.lo_encrypt_key_size = 0;
+		break;
+	case LO_CRYPT_XOR:
+		pass = xgetpass(pfd, "Password: ");
+		goto gotpass;
+	default:
+		pass = xgetpass(pfd, "Password: ");
+	gotpass:
+		memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE);
+		xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
+		memset(pass, 0, strlen(pass));
+		loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE;
+	}
+
+	if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
+		perror("ioctl: LOOP_SET_FD");
+		return 1;
+	}
+	close (ffd);
+
+	i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64);
+	if (i) {
+		struct loop_info loopinfo;
+		int errsv = errno;
+
+		i = loop_info64_to_old(&loopinfo64, &loopinfo);
+		if (i) {
+			errno = errsv;
+			perror("ioctl: LOOP_SET_STATUS64");
+		} else {
+			i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
+			if (i)
+				perror("ioctl: LOOP_SET_STATUS");
+		}
+		memset(&loopinfo, 0, sizeof(loopinfo));
+	}
+	memset(&loopinfo64, 0, sizeof(loopinfo64));
+
+	if (i) {
+		ioctl (fd, LOOP_CLR_FD, 0);
+		close (fd);
+		return 1;
+	}
+	close (fd);
+
+	if (verbose > 1)
+		printf("set_loop(%s,%s,%llu): success\n",
+		       device, file, offset);
+	return 0;
+}
+
+int del_loop (const char *device)
+{
+	int fd;
+
+	if ((fd = open (device, O_RDONLY)) < 0) {
+		int errsv = errno;
+		fprintf(stderr, "loop: can't delete device %s: %s\n",
+			device, strerror (errsv));
+		return 1;
+	}
+	if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
+		perror ("ioctl: LOOP_CLR_FD");
+		return 1;
+	}
+	close (fd);
+	if (verbose > 1)
+		printf("del_loop(%s): success\n", device);
+	return 0;
+}
+
+
+#include <getopt.h>
+#include <stdarg.h>
+
+int verbose = 0;
+char *progname;
+
+static void usage(void) {
+	fprintf(stderr, "usage:\n\
+  %s loop_device                                       # give info\n\
+  %s -d loop_device                                    # delete\n\
+  %s -f                                                # find unused\n\
+  %s [-e encryption] [-o offset] {-f|loop_device} file # setup\n",
+		progname, progname, progname, progname);
+	exit(1);
+}
+
+char * xstrdup (const char *s) {
+	char *t;
+
+	if (s == NULL)
+		return NULL;
+
+	t = strdup (s);
+
+	if (t == NULL) {
+		fprintf(stderr, "not enough memory");
+		exit(1);
+	}
+
+	return t;
+}
+
+void error (const char *fmt, ...)
+{
+	va_list args;
+
+	va_start (args, fmt);
+	vfprintf (stderr, fmt, args);
+	va_end (args);
+	fprintf (stderr, "\n");
+}
+
+int main(int argc, char **argv)
+{
+	char *p, *offset, *encryption, *passfd, *device, *file;
+	int delete, find, c;
+	int res = 0;
+	int ro = 0;
+	int pfd = -1;
+	unsigned long long off;
+
+
+	delete = find = 0;
+	off = 0;
+	offset = encryption = passfd = NULL;
+
+	progname = argv[0];
+	if ((p = strrchr(progname, '/')) != NULL)
+		progname = p+1;
+
+	while ((c = getopt(argc, argv, "de:E:fo:p:v")) != -1) {
+		switch (c) {
+		case 'd':
+			delete = 1;
+			break;
+		case 'E':
+		case 'e':
+			encryption = optarg;
+			break;
+		case 'f':
+			find = 1;
+			break;
+		case 'o':
+			offset = optarg;
+			break;
+		case 'p':
+			passfd = optarg;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		default:
+			usage();
+		}
+	}
+
+	if (argc == 1) {
+		usage();
+	} else if (delete) {
+		if (argc != optind+1 || encryption || offset || find)
+			usage();
+	} else if (find) {
+		if (argc < optind || argc > optind+1)
+			usage();
+	} else {
+		if (argc < optind+1 || argc > optind+2)
+			usage();
+	}
+
+	if (find) {
+		device = find_unused_loop_device();
+		if (device == NULL)
+			return -1;
+		if (verbose)
+			printf("Loop device is %s\n", device);
+		if (argc == optind) {
+			printf("%s\n", device);
+			return 0;
+		}
+		file = argv[optind];
+	} else {
+		device = argv[optind];
+		if (argc == optind+1)
+			file = NULL;
+		else
+			file = argv[optind+1];
+	}
+
+	if (delete)
+		res = del_loop(device);
+	else if (file == NULL)
+		res = show_loop(device);
+	else {
+		if (offset && sscanf(offset, "%llu", &off) != 1)
+			usage();
+		if (passfd && sscanf(passfd, "%d", &pfd) != 1)
+			usage();
+		res = set_loop(device, file, off, encryption, pfd, &ro);
+	}
+	return res;
+}

commit 08d45001cfa46db79e3d1b5fc6ecea0085ab024c
Author: Thomas Bächler <thomas at archlinux.org>
Date:   Sun Mar 14 03:26:56 2010 +0100

    klcc: compile shared by default
    
    patch was shipped in Archlinux.
    it is easily overidable by cli, but shared binaries seem better default.
    
    Signed-off-by: maximilian attems <max at stro.at>

diff --git a/klcc/klcc.in b/klcc/klcc.in
index d4313a5..b2c5daf 100644
--- a/klcc/klcc.in
+++ b/klcc/klcc.in
@@ -113,7 +113,7 @@ undef $lang;
 
 $save_temps = 0;		# The -save-temps option
 $verbose = 0;			# The -v option
-$shared = 0;	   		# Are we compiling shared?
+$shared = 1;	   		# Default to compiling shared
 $debugging = 0;	   		# -g or -p option present?
 $strip = 0;			# -s option present?
 undef $output;			# -o option present?



More information about the klibc mailing list