1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
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
|