summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2014-07-29 22:01:36 -0400
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2014-07-31 04:00:31 -0400
commita2a5291b3f5ab6ed4c92f51d0fd10a03047380d8 (patch)
tree1a74a85c70861b0a411d9dd325b039976de4fd4e /src/shared
parent73381fcf54e38456067f0e87b8611a21eff99169 (diff)
Reject invalid quoted strings
String which ended in an unfinished quote were accepted, potentially with bad memory accesses. Reject anything which ends in a unfished quote, or contains non-whitespace characters right after the closing quote. _FOREACH_WORD now returns the invalid character in *state. But this return value is not checked anywhere yet. Also, make 'word' and 'state' variables const pointers, and rename 'w' to 'word' in various places. Things are easier to read if the same name is used consistently. mbiebl_> am I correct that something like this doesn't work mbiebl_> ExecStart=/usr/bin/encfs --extpass='/bin/systemd-ask-passwd "Unlock EncFS"' mbiebl_> systemd seems to strip of the quotes mbiebl_> systemctl status shows mbiebl_> ExecStart=/usr/bin/encfs --extpass='/bin/systemd-ask-password Unlock EncFS $RootDir $MountPoint mbiebl_> which is pretty weird
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/cgroup-util.c12
-rw-r--r--src/shared/condition-util.c3
-rw-r--r--src/shared/conf-parser.c7
-rw-r--r--src/shared/conf-parser.h6
-rw-r--r--src/shared/install.c7
-rw-r--r--src/shared/log.c6
-rw-r--r--src/shared/path-util.c6
-rw-r--r--src/shared/sleep-config.c19
-rw-r--r--src/shared/strv.c21
-rw-r--r--src/shared/util.c47
-rw-r--r--src/shared/util.h4
11 files changed, 79 insertions, 59 deletions
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index c1c4d409ae..f683ae990e 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -753,9 +753,9 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
cs = strlen(controller);
FOREACH_LINE(line, f, return -errno) {
- char *l, *p, *w, *e;
+ char *l, *p, *e;
size_t k;
- char *state;
+ const char *word, *state;
bool found = false;
truncate_nl(line);
@@ -771,16 +771,16 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
*e = 0;
- FOREACH_WORD_SEPARATOR(w, k, l, ",", state) {
+ FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
- if (k == cs && memcmp(w, controller, cs) == 0) {
+ if (k == cs && memcmp(word, controller, cs) == 0) {
found = true;
break;
}
if (k == 5 + cs &&
- memcmp(w, "name=", 5) == 0 &&
- memcmp(w+5, controller, cs) == 0) {
+ memcmp(word, "name=", 5) == 0 &&
+ memcmp(word+5, controller, cs) == 0) {
found = true;
break;
}
diff --git a/src/shared/condition-util.c b/src/shared/condition-util.c
index 928edeeb9d..f88ddc19e2 100644
--- a/src/shared/condition-util.c
+++ b/src/shared/condition-util.c
@@ -74,7 +74,8 @@ void condition_free_list(Condition *first) {
}
bool condition_test_kernel_command_line(Condition *c) {
- char *line, *w, *state, *word = NULL;
+ char *line, *word = NULL;
+ const char *w, *state;
bool equal;
int r;
size_t l, pl;
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 0be7226871..cd189adfc3 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -675,7 +675,8 @@ int config_parse_strv(const char *unit,
void *data,
void *userdata) {
- char *** sv = data, *w, *state;
+ char ***sv = data;
+ const char *word, *state;
size_t l;
int r;
@@ -700,10 +701,10 @@ int config_parse_strv(const char *unit,
return 0;
}
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+ FOREACH_WORD_QUOTED(word, l, rvalue, state) {
char *n;
- n = strndup(w, l);
+ n = strndup(word, l);
if (!n)
return log_oom();
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index ea7b710dec..a17dde9069 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -170,7 +170,7 @@ int log_syntax_internal(const char *unit, int level,
void *userdata) { \
\
type **enums = data, *xs, x, *ys; \
- char *w, *state; \
+ const char *word, *state; \
size_t l, i = 0; \
\
assert(filename); \
@@ -181,10 +181,10 @@ int log_syntax_internal(const char *unit, int level,
xs = new0(type, 1); \
*xs = invalid; \
\
- FOREACH_WORD(w, l, rvalue, state) { \
+ FOREACH_WORD(word, l, rvalue, state) { \
_cleanup_free_ char *en = NULL; \
\
- en = strndup(w, l); \
+ en = strndup(word, l); \
if (!en) \
return -ENOMEM; \
\
diff --git a/src/shared/install.c b/src/shared/install.c
index cc61c01e20..c32d6599a6 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -946,20 +946,19 @@ static int config_parse_also(
void *data,
void *userdata) {
- char *w;
size_t l;
- char *state;
+ const char *word, *state;
InstallContext *c = data;
assert(filename);
assert(lvalue);
assert(rvalue);
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+ FOREACH_WORD_QUOTED(word, l, rvalue, state) {
_cleanup_free_ char *n;
int r;
- n = strndup(w, l);
+ n = strndup(word, l);
if (!n)
return -ENOMEM;
diff --git a/src/shared/log.c b/src/shared/log.c
index 3941e3e1c2..a7c3195f39 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -871,11 +871,11 @@ void log_parse_environment(void) {
if (r < 0)
log_warning("Failed to read /proc/cmdline. Ignoring: %s", strerror(-r));
else if (r > 0) {
- char *w, *state;
+ const char *word, *state;
size_t l;
- FOREACH_WORD_QUOTED(w, l, line, state) {
- if (l == 5 && startswith(w, "debug")) {
+ FOREACH_WORD_QUOTED(word, l, line, state) {
+ if (l == 5 && startswith(word, "debug")) {
log_set_max_level(LOG_DEBUG);
break;
}
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 5bc5012fe8..57554cd294 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -574,7 +574,7 @@ int find_binary(const char *name, char **filename) {
return 0;
} else {
const char *path;
- char *state, *w;
+ const char *word, *state;
size_t l;
/**
@@ -585,10 +585,10 @@ int find_binary(const char *name, char **filename) {
if (!path)
path = DEFAULT_PATH;
- FOREACH_WORD_SEPARATOR(w, l, path, ":", state) {
+ FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
_cleanup_free_ char *p = NULL;
- if (asprintf(&p, "%.*s/%s", (int) l, w, name) < 0)
+ if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
return -ENOMEM;
if (access(p, X_OK) < 0)
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 16a488d56b..d8de644a92 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -98,7 +98,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
}
int can_sleep_state(char **types) {
- char *w, *state, **type;
+ char **type;
int r;
_cleanup_free_ char *p = NULL;
@@ -114,11 +114,12 @@ int can_sleep_state(char **types) {
return false;
STRV_FOREACH(type, types) {
+ const char *word, *state;
size_t l, k;
k = strlen(*type);
- FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
- if (l == k && memcmp(w, *type, l) == 0)
+ FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state)
+ if (l == k && memcmp(word, *type, l) == 0)
return true;
}
@@ -126,7 +127,7 @@ int can_sleep_state(char **types) {
}
int can_sleep_disk(char **types) {
- char *w, *state, **type;
+ char **type;
int r;
_cleanup_free_ char *p = NULL;
@@ -142,14 +143,18 @@ int can_sleep_disk(char **types) {
return false;
STRV_FOREACH(type, types) {
+ const char *word, *state;
size_t l, k;
k = strlen(*type);
- FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
- if (l == k && memcmp(w, *type, l) == 0)
+ FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state) {
+ if (l == k && memcmp(word, *type, l) == 0)
return true;
- if (l == k + 2 && w[0] == '[' && memcmp(w + 1, *type, l - 2) == 0 && w[l-1] == ']')
+ if (l == k + 2 &&
+ word[0] == '[' &&
+ memcmp(word + 1, *type, l - 2) == 0 &&
+ word[l-1] == ']')
return true;
}
}
diff --git a/src/shared/strv.c b/src/shared/strv.c
index b4c476eff2..0ac66b927c 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -201,8 +201,7 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
}
char **strv_split(const char *s, const char *separator) {
- char *state;
- char *w;
+ const char *word, *state;
size_t l;
unsigned n, i;
char **r;
@@ -210,7 +209,7 @@ char **strv_split(const char *s, const char *separator) {
assert(s);
n = 0;
- FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
+ FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
n++;
r = new(char*, n+1);
@@ -218,8 +217,8 @@ char **strv_split(const char *s, const char *separator) {
return NULL;
i = 0;
- FOREACH_WORD_SEPARATOR(w, l, s, separator, state) {
- r[i] = strndup(w, l);
+ FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
+ r[i] = strndup(word, l);
if (!r[i]) {
strv_free(r);
return NULL;
@@ -233,8 +232,7 @@ char **strv_split(const char *s, const char *separator) {
}
char **strv_split_quoted(const char *s) {
- char *state;
- char *w;
+ const char *word, *state;
size_t l;
unsigned n, i;
char **r;
@@ -242,16 +240,19 @@ char **strv_split_quoted(const char *s) {
assert(s);
n = 0;
- FOREACH_WORD_QUOTED(w, l, s, state)
+ FOREACH_WORD_QUOTED(word, l, s, state)
n++;
+ if (*state)
+ /* bad syntax */
+ return NULL;
r = new(char*, n+1);
if (!r)
return NULL;
i = 0;
- FOREACH_WORD_QUOTED(w, l, s, state) {
- r[i] = cunescape_length(w, l);
+ FOREACH_WORD_QUOTED(word, l, s, state) {
+ r[i] = cunescape_length(word, l);
if (!r[i]) {
strv_free(r);
return NULL;
diff --git a/src/shared/util.c b/src/shared/util.c
index d8a75bdc6a..cb9687cb02 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -415,37 +415,50 @@ static size_t strcspn_escaped(const char *s, const char *reject) {
else if (s[n] == '\\')
escaped = true;
else if (strchr(reject, s[n]))
- return n;
+ break;
}
- return n;
+ /* if s ends in \, return index of previous char */
+ return n - escaped;
}
/* Split a string into words. */
-char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state) {
- char *current;
+const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
+ const char *current;
- current = *state ? *state : (char*) c;
+ current = *state;
- if (!*current || *c == 0)
+ if (!*current) {
+ assert(**state == '\0');
return NULL;
+ }
current += strspn(current, separator);
- if (!*current)
+ if (!*current) {
+ *state = current;
return NULL;
+ }
if (quoted && strchr("\'\"", *current)) {
- char quotechar = *(current++);
- *l = strcspn_escaped(current, (char[]){quotechar, '\0'});
- *state = current+*l+1;
+ char quotechars[2] = {*current, '\0'};
+
+ *l = strcspn_escaped(current + 1, quotechars);
+ if (current[*l + 1] == '\0' ||
+ (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+ /* right quote missing or garbage at the end*/
+ *state = current;
+ return NULL;
+ }
+ assert(current[*l + 1] == quotechars[0]);
+ *state = current++ + *l + 2;
} else if (quoted) {
*l = strcspn_escaped(current, separator);
- *state = current+*l;
+ *state = current + *l;
} else {
*l = strcspn(current, separator);
- *state = current+*l;
+ *state = current + *l;
}
- return (char*) current;
+ return current;
}
int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
@@ -6059,7 +6072,7 @@ int split_pair(const char *s, const char *sep, char **l, char **r) {
int shall_restore_state(void) {
_cleanup_free_ char *line = NULL;
- char *w, *state;
+ const char *word, *state;
size_t l;
int r;
@@ -6071,12 +6084,12 @@ int shall_restore_state(void) {
r = 1;
- FOREACH_WORD_QUOTED(w, l, line, state) {
+ FOREACH_WORD_QUOTED(word, l, line, state) {
const char *e;
char n[l+1];
int k;
- memcpy(n, w, l);
+ memcpy(n, word, l);
n[l] = 0;
e = startswith(n, "systemd.restore_state=");
@@ -6120,7 +6133,7 @@ int proc_cmdline(char **ret) {
int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
_cleanup_free_ char *line = NULL;
- char *w, *state;
+ const char *w, *state;
size_t l;
int r;
diff --git a/src/shared/util.h b/src/shared/util.h
index 81da59b20c..45294800e4 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -234,7 +234,7 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
return safe_atolli(s, (long long int*) ret_i);
}
-char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state);
+const char* split(const char **state, size_t *l, const char *separator, bool quoted);
#define FOREACH_WORD(word, length, s, state) \
_FOREACH_WORD(word, length, s, WHITESPACE, false, state)
@@ -249,7 +249,7 @@ char *split(const char *c, size_t *l, const char *separator, bool quoted, char *
_FOREACH_WORD(word, length, s, separator, true, state)
#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
- for ((state) = NULL, (word) = split((s), &(length), (separator), (quoted), &(state)); (word); (word) = split((s), &(length), (separator), (quoted), &(state)))
+ for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
int get_starttime_of_pid(pid_t pid, unsigned long long *st);