diff options
Diffstat (limited to 'src/misc')
| -rw-r--r-- | src/misc/getopt.c | 3 | ||||
| -rw-r--r-- | src/misc/getrlimit.c | 8 | ||||
| -rw-r--r-- | src/misc/initgroups.c | 26 | ||||
| -rw-r--r-- | src/misc/ioctl.c | 9 | ||||
| -rw-r--r-- | src/misc/lockf.c | 2 | ||||
| -rw-r--r-- | src/misc/mntent.c | 66 | ||||
| -rw-r--r-- | src/misc/nftw.c | 6 | ||||
| -rw-r--r-- | src/misc/setrlimit.c | 8 | ||||
| -rw-r--r-- | src/misc/syslog.c | 3 | 
9 files changed, 105 insertions, 26 deletions
| diff --git a/src/misc/getopt.c b/src/misc/getopt.c index c3f66995..b02b81c3 100644 --- a/src/misc/getopt.c +++ b/src/misc/getopt.c @@ -87,7 +87,8 @@ int getopt(int argc, char * const argv[], const char *optstring)  	if (optstring[i] == ':') {  		optarg = 0;  		if (optstring[i+1] != ':' || optpos) { -			optarg = argv[optind++] + optpos; +			optarg = argv[optind++]; +			if (optpos) optarg += optpos;  			optpos = 0;  		}  		if (optind > argc) { diff --git a/src/misc/getrlimit.c b/src/misc/getrlimit.c index 2ab2f0f4..a5558d81 100644 --- a/src/misc/getrlimit.c +++ b/src/misc/getrlimit.c @@ -6,12 +6,13 @@  int getrlimit(int resource, struct rlimit *rlim)  { -	unsigned long k_rlim[2];  	int ret = syscall(SYS_prlimit64, 0, resource, 0, rlim);  	if (!ret) {  		FIX(rlim->rlim_cur);  		FIX(rlim->rlim_max);  	} +#ifdef SYS_getrlimit +	unsigned long k_rlim[2];  	if (!ret || errno != ENOSYS)  		return ret;  	if (syscall(SYS_getrlimit, resource, k_rlim) < 0) @@ -21,6 +22,7 @@ int getrlimit(int resource, struct rlimit *rlim)  	FIX(rlim->rlim_cur);  	FIX(rlim->rlim_max);  	return 0; +#else +	return ret; +#endif  } - -weak_alias(getrlimit, getrlimit64); diff --git a/src/misc/initgroups.c b/src/misc/initgroups.c index 922a9581..101f5c7b 100644 --- a/src/misc/initgroups.c +++ b/src/misc/initgroups.c @@ -1,11 +1,29 @@  #define _GNU_SOURCE  #include <grp.h>  #include <limits.h> +#include <stdlib.h>  int initgroups(const char *user, gid_t gid)  { -	gid_t groups[NGROUPS_MAX]; -	int count = NGROUPS_MAX; -	if (getgrouplist(user, gid, groups, &count) < 0) return -1; -	return setgroups(count, groups); +	gid_t buf[32], *groups = buf; +	int count = sizeof buf / sizeof *buf, prev_count = count; +	while (getgrouplist(user, gid, groups, &count) < 0) { +		if (groups != buf) free(groups); + +		/* Return if failure isn't buffer size */ +		if (count <= prev_count) +			return -1; + +		/* Always increase by at least 50% to limit to +		 * logarithmically many retries on TOCTOU races. */ +		if (count < prev_count + (prev_count>>1)) +			count = prev_count + (prev_count>>1); + +		groups = calloc(count, sizeof *groups); +		if (!groups) return -1; +		prev_count = count; +	} +	int ret = setgroups(count, groups); +	if (groups != buf) free(groups); +	return ret;  } diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c index 49282811..35804f02 100644 --- a/src/misc/ioctl.c +++ b/src/misc/ioctl.c @@ -6,6 +6,7 @@  #include <stddef.h>  #include <stdint.h>  #include <string.h> +#include <endian.h>  #include "syscall.h"  #define alignof(t) offsetof(struct { char c; t x; }, x) @@ -53,7 +54,7 @@ static const struct ioctl_compat_map compat_map[] = {  	{ _IOWR('A', 0x23, char[136]), _IOWR('A', 0x23, char[132]), 0, WR, 1, 0 },  	{ 0, 0, 4, WR, 1, 0 }, /* snd_pcm_sync_ptr (flags only) */  	{ 0, 0, 32, WR, 1, OFFS(8,12,16,24,28) }, /* snd_pcm_mmap_status */ -	{ 0, 0, 8, WR, 1, OFFS(0,4) }, /* snd_pcm_mmap_control */ +	{ 0, 0, 4, WR, 1, 0 }, /* snd_pcm_mmap_control (each member) */  	/* VIDIOC_QUERYBUF, VIDIOC_QBUF, VIDIOC_DQBUF, VIDIOC_PREPARE_BUF */  	{ _IOWR('V',  9, new_misaligned(68)), _IOWR('V',  9, char[68]), 68, WR, 1, OFFS(20, 24) }, @@ -90,7 +91,11 @@ static void convert_ioctl_struct(const struct ioctl_compat_map *map, char *old,  		 * if another exception appears this needs changing. */  		convert_ioctl_struct(map+1, old, new, dir);  		convert_ioctl_struct(map+2, old+4, new+8, dir); -		convert_ioctl_struct(map+3, old+68, new+72, dir); +		/* snd_pcm_mmap_control, special-cased due to kernel +		 * type definition having been botched. */ +		int adj = BYTE_ORDER==BIG_ENDIAN ? 4 : 0; +		convert_ioctl_struct(map+3, old+68, new+72+adj, dir); +		convert_ioctl_struct(map+3, old+72, new+76+3*adj, dir);  		return;  	}  	for (int i=0; i < map->noffs; i++) { diff --git a/src/misc/lockf.c b/src/misc/lockf.c index 16a80bec..0162442b 100644 --- a/src/misc/lockf.c +++ b/src/misc/lockf.c @@ -28,5 +28,3 @@ int lockf(int fd, int op, off_t size)  	errno = EINVAL;  	return -1;  } - -weak_alias(lockf, lockf64); diff --git a/src/misc/mntent.c b/src/misc/mntent.c index eabb8200..76f9c162 100644 --- a/src/misc/mntent.c +++ b/src/misc/mntent.c @@ -2,6 +2,7 @@  #include <string.h>  #include <mntent.h>  #include <errno.h> +#include <limits.h>  static char *internal_buf;  static size_t internal_bufsize; @@ -19,9 +20,46 @@ int endmntent(FILE *f)  	return 1;  } +static char *unescape_ent(char *beg) +{ +	char *dest = beg; +	const char *src = beg; +	while (*src) { +		const char *val; +		unsigned char cval = 0; +		if (*src != '\\') { +			*dest++ = *src++; +			continue; +		} +		if (src[1] == '\\') { +			++src; +			*dest++ = *src++; +			continue; +		} +		val = src + 1; +		for (int i = 0; i < 3; ++i) { +			if (*val >= '0' && *val <= '7') { +				cval <<= 3; +				cval += *val++ - '0'; +			} else { +				break; +			} +		} +		if (cval) { +			*dest++ = cval; +			src = val; +		} else { +			*dest++ = *src++; +		} +	} +	*dest = 0; +	return beg; +} +  struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)  { -	int cnt, n[8], use_internal = (linebuf == SENTINEL); +	int n[8], use_internal = (linebuf == SENTINEL); +	size_t len, i;  	mnt->mnt_freq = 0;  	mnt->mnt_passno = 0; @@ -39,20 +77,24 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle  			errno = ERANGE;  			return 0;  		} -		cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + +		len = strlen(linebuf); +		if (len > INT_MAX) continue; +		for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len; +		sscanf(linebuf, " %n%*[^ \t\n]%n %n%*[^ \t\n]%n %n%*[^ \t\n]%n %n%*[^ \t\n]%n %d %d",  			n, n+1, n+2, n+3, n+4, n+5, n+6, n+7,  			&mnt->mnt_freq, &mnt->mnt_passno); -	} while (cnt < 2 || linebuf[n[0]] == '#'); +	} while (linebuf[n[0]] == '#' || n[1]==len);  	linebuf[n[1]] = 0;  	linebuf[n[3]] = 0;  	linebuf[n[5]] = 0;  	linebuf[n[7]] = 0; -	mnt->mnt_fsname = linebuf+n[0]; -	mnt->mnt_dir = linebuf+n[2]; -	mnt->mnt_type = linebuf+n[4]; -	mnt->mnt_opts = linebuf+n[6]; +	mnt->mnt_fsname = unescape_ent(linebuf+n[0]); +	mnt->mnt_dir = unescape_ent(linebuf+n[2]); +	mnt->mnt_type = unescape_ent(linebuf+n[4]); +	mnt->mnt_opts = unescape_ent(linebuf+n[6]);  	return mnt;  } @@ -73,5 +115,13 @@ int addmntent(FILE *f, const struct mntent *mnt)  char *hasmntopt(const struct mntent *mnt, const char *opt)  { -	return strstr(mnt->mnt_opts, opt); +	size_t l = strlen(opt); +	char *p = mnt->mnt_opts; +	for (;;) { +		if (!strncmp(p, opt, l) && (!p[l] || p[l]==',' || p[l]=='=')) +			return p; +		p = strchr(p, ','); +		if (!p) return 0; +		p++; +	}  } diff --git a/src/misc/nftw.c b/src/misc/nftw.c index 8dcff7fe..71bc62ee 100644 --- a/src/misc/nftw.c +++ b/src/misc/nftw.c @@ -31,6 +31,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,  	int err;  	struct FTW lev; +	st.st_dev = st.st_ino = 0; +  	if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {  		if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))  			type = FTW_SLN; @@ -46,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,  		type = FTW_F;  	} -	if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev) +	if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev)  		return 0;  	new.chain = h; @@ -138,5 +140,3 @@ int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, str  	pthread_setcancelstate(cs, 0);  	return r;  } - -weak_alias(nftw, nftw64); diff --git a/src/misc/setrlimit.c b/src/misc/setrlimit.c index 8340aee0..edb413fa 100644 --- a/src/misc/setrlimit.c +++ b/src/misc/setrlimit.c @@ -12,12 +12,14 @@ struct ctx {  	int err;  }; +#ifdef SYS_setrlimit  static void do_setrlimit(void *p)  {  	struct ctx *c = p;  	if (c->err>0) return;  	c->err = -__syscall(SYS_setrlimit, c->res, c->lim);  } +#endif  int setrlimit(int resource, const struct rlimit *rlim)  { @@ -29,6 +31,7 @@ int setrlimit(int resource, const struct rlimit *rlim)  		rlim = &tmp;  	}  	int ret = __syscall(SYS_prlimit64, 0, resource, rlim, 0); +#ifdef SYS_setrlimit  	if (ret != -ENOSYS) return __syscall_ret(ret);  	struct ctx c = { @@ -42,6 +45,7 @@ int setrlimit(int resource, const struct rlimit *rlim)  		return -1;  	}  	return 0; +#else +	return __syscall_ret(ret); +#endif  } - -weak_alias(setrlimit, setrlimit64); diff --git a/src/misc/syslog.c b/src/misc/syslog.c index 7dc0c1be..710202f9 100644 --- a/src/misc/syslog.c +++ b/src/misc/syslog.c @@ -11,6 +11,7 @@  #include <fcntl.h>  #include "lock.h"  #include "fork_impl.h" +#include "locale_impl.h"  static volatile int lock[1];  static char log_ident[32]; @@ -99,7 +100,7 @@ static void _vsyslog(int priority, const char *message, va_list ap)  	now = time(NULL);  	gmtime_r(&now, &tm); -	strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); +	strftime_l(timebuf, sizeof timebuf, "%b %e %T", &tm, C_LOCALE);  	pid = (log_opt & LOG_PID) ? getpid() : 0;  	l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", | 
