aboutsummaryrefslogblamecommitdiffstats
path: root/main/alsa-lib/0001-snd_user_file-avoid-use-wordexp.patch
blob: 9205aa215de1c4a534e4ea24011e2bddcd16a8fb (plain) (tree)
































































































































                                                                                            
From 1f9113336e8eb4bd89ca040e90c5fdc79b0c567f Mon Sep 17 00:00:00 2001
From: Natanael Copa <ncopa@alpinelinux.org>
Date: Tue, 11 Jul 2017 18:25:13 +0200
Subject: [PATCH] snd_user_file: avoid use wordexp

As suggested in POSIX[1], wordexp might execute the shell. If the libc
implementation does so, it will break the firefox sandbox which does
not allow exec. This happened on Alpine Linux with musl libc[2].

Since we cannot guarantee that the system wordexp implementation does
not execute shell, we cannot really use it, and need to implement the
~/ expansion ourselves.

[1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html#tag_16_684_08
[2]: http://bugs.alpinelinux.org/issues/7454#note-2

Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
---
 src/userfile.c | 77 +++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 47 insertions(+), 30 deletions(-)

diff --git a/src/userfile.c b/src/userfile.c
index 72779da4..0e3f5fae 100644
--- a/src/userfile.c
+++ b/src/userfile.c
@@ -21,6 +21,11 @@
 #include <config.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 /**
  * \brief Get the full file name
@@ -28,46 +33,58 @@
  * \param result The pointer to store the resultant file name
  * \return 0 if successful, or a negative error code
  *
- * Parses the given file name with POSIX-Shell-like expansion and
- * stores the first matchine one.  The returned string is strdup'ed.
+ * Parses the given file name with POSIX-Shell-like expansion for ~/.
+ * The returned string is strdup'ed.
  */
 
-#ifdef HAVE_WORDEXP_H
-#include <wordexp.h>
 #include <assert.h>
 int snd_user_file(const char *file, char **result)
 {
-	wordexp_t we;
 	int err;
-	
+	size_t len;
+	char *buf = NULL;
+
 	assert(file && result);
-	err = wordexp(file, &we, WRDE_NOCMD);
-	switch (err) {
-	case WRDE_NOSPACE:
-		wordfree(&we);
-		return -ENOMEM;
-	case 0:
-		if (we.we_wordc == 1)
-			break;
-		wordfree(&we);
-		/* fall thru */
-	default:
-		return -EINVAL;
+	*result = NULL;
+
+	/* expand ~/ if needed */
+	if (file[0] == '~' && file[1] == '/') {
+		const char *home = getenv("HOME");
+		if (home == NULL) {
+			struct passwd pwent, *p = NULL;
+			uid_t id = getuid();
+			size_t bufsize = 1024;
+
+			buf = malloc(bufsize);
+			if (buf == NULL)
+				goto out;
+
+			while ((err = getpwuid_r(id, &pwent, buf, bufsize, &p)) == ERANGE) {
+				char *newbuf;
+				bufsize += 1024;
+				if (bufsize < 1024)
+					break;
+				newbuf = realloc(buf, bufsize);
+				if (newbuf == NULL)
+					goto out;
+				buf = newbuf;
+			}
+			home = err ? "" : pwent.pw_dir;
+		}
+		len = strlen(home) + strlen(&file[2]) + 2;
+		*result = malloc(len);
+		if (*result)
+			snprintf(*result, len, "%s/%s", home, &file[2]);
+	} else {
+		*result = strdup(file);
 	}
-	*result = strdup(we.we_wordv[0]);
-	wordfree(&we);
+
+out:
+	if (buf)
+		free(buf);
+
 	if (*result == NULL)
 		return -ENOMEM;
 	return 0;
 }
 
-#else /* !HAVE_WORDEXP_H */
-/* just copy the string - would be nicer to expand by ourselves, though... */
-int snd_user_file(const char *file, char **result)
-{
-	*result = strdup(file);
-	if (! *result)
-		return -ENOMEM;
-	return 0;
-}
-#endif /* HAVE_WORDEXP_H */
-- 
2.13.2