Fix some potential misuses of ast_str in the code.

Passing an ast_str pointer by value that then calls
ast_str_set(), ast_str_set_va(), ast_str_append(), or
ast_str_append_va() can result in the pointer originally
passed by value being invalidated if the ast_str had
to be reallocated.

This fixes places in the code that do this. Only the
example in ccss.c could result in pointer invalidation
though since the other cases use a stack-allocated ast_str
and cannot be reallocated.

I've also updated the doxygen in strings.h to include
notes about potential misuse of the functions mentioned
previously.

Review: https://reviewboard.asterisk.org/r/2161
........

Merged revisions 375025 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 375026 from http://svn.asterisk.org/svn/asterisk/branches/10
........

Merged revisions 375027 from http://svn.asterisk.org/svn/asterisk/branches/11


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@375044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Michelson
2012-10-15 21:25:29 +00:00
parent e41a591dfc
commit e9ab568f88
4 changed files with 47 additions and 26 deletions

View File

@@ -709,7 +709,7 @@ struct chanlist {
AST_LIST_HEAD_NOLOCK(dial_head, chanlist); AST_LIST_HEAD_NOLOCK(dial_head, chanlist);
static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode); static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode);
static void chanlist_free(struct chanlist *outgoing) static void chanlist_free(struct chanlist *outgoing)
{ {
@@ -1606,7 +1606,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
} }
if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) && if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
detect_disconnect(in, f->subclass.integer, featurecode)) { detect_disconnect(in, f->subclass.integer, &featurecode)) {
ast_verb(3, "User requested call disconnect.\n"); ast_verb(3, "User requested call disconnect.\n");
*to = 0; *to = 0;
strcpy(pa->status, "CANCEL"); strcpy(pa->status, "CANCEL");
@@ -1721,18 +1721,18 @@ skip_frame:;
return peer; return peer;
} }
static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode) static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode)
{ {
struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */ struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */
struct ast_call_feature feature = { 0, }; struct ast_call_feature feature = { 0, };
int res; int res;
ast_str_append(&featurecode, 1, "%c", code); ast_str_append(featurecode, 1, "%c", code);
res = ast_feature_detect(chan, &features, ast_str_buffer(featurecode), &feature); res = ast_feature_detect(chan, &features, ast_str_buffer(*featurecode), &feature);
if (res != AST_FEATURE_RETURN_STOREDIGITS) { if (res != AST_FEATURE_RETURN_STOREDIGITS) {
ast_str_reset(featurecode); ast_str_reset(*featurecode);
} }
if (feature.feature_mask & AST_FEATURE_DISCONNECT) { if (feature.feature_mask & AST_FEATURE_DISCONNECT) {
return 1; return 1;

View File

@@ -1597,19 +1597,19 @@ static int send_ping(const void *data)
return 0; return 0;
} }
static void encmethods_to_str(int e, struct ast_str *buf) static void encmethods_to_str(int e, struct ast_str **buf)
{ {
ast_str_set(&buf, 0, "("); ast_str_set(buf, 0, "(");
if (e & IAX_ENCRYPT_AES128) { if (e & IAX_ENCRYPT_AES128) {
ast_str_append(&buf, 0, "aes128"); ast_str_append(buf, 0, "aes128");
} }
if (e & IAX_ENCRYPT_KEYROTATE) { if (e & IAX_ENCRYPT_KEYROTATE) {
ast_str_append(&buf, 0, ",keyrotate"); ast_str_append(buf, 0, ",keyrotate");
} }
if (ast_str_strlen(buf) > 1) { if (ast_str_strlen(*buf) > 1) {
ast_str_append(&buf, 0, ")"); ast_str_append(buf, 0, ")");
} else { } else {
ast_str_set(&buf, 0, "No"); ast_str_set(buf, 0, "No");
} }
} }
@@ -3829,7 +3829,7 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
ast_sockaddr_to_sin(&peer->addr, &peer_addr); ast_sockaddr_to_sin(&peer->addr, &peer_addr);
encmethods_to_str(peer->encmethods, encmethods); encmethods_to_str(peer->encmethods, &encmethods);
ast_cli(a->fd, "\n\n"); ast_cli(a->fd, "\n\n");
ast_cli(a->fd, " * Name : %s\n", peer->name); ast_cli(a->fd, " * Name : %s\n", peer->name);
ast_cli(a->fd, " Description : %s\n", peer->description); ast_cli(a->fd, " Description : %s\n", peer->description);
@@ -6811,7 +6811,7 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
else else
ast_copy_string(name, peer->name, sizeof(name)); ast_copy_string(name, peer->name, sizeof(name));
encmethods_to_str(peer->encmethods, encmethods); encmethods_to_str(peer->encmethods, &encmethods);
retstatus = peer_status(peer, status, sizeof(status)); retstatus = peer_status(peer, status, sizeof(status));
if (retstatus > 0) if (retstatus > 0)
online_peers++; online_peers++;
@@ -7116,7 +7116,7 @@ static int manager_iax2_show_peer_list(struct mansession *s, const struct messag
i = ao2_iterator_init(peers, 0); i = ao2_iterator_init(peers, 0);
for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) { for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
encmethods_to_str(peer->encmethods, encmethods); encmethods_to_str(peer->encmethods, &encmethods);
astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext); astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext);
if (!ast_strlen_zero(peer->username)) { if (!ast_strlen_zero(peer->username)) {
astman_append(s, "ObjectName: %s\r\nObjectUsername: %s\r\n", peer->name, peer->username); astman_append(s, "ObjectName: %s\r\nObjectUsername: %s\r\n", peer->name, peer->username);
@@ -14781,7 +14781,7 @@ static int peers_data_provider_get(const struct ast_data_search *search,
ast_data_add_bool(data_peer, "dynamic", ast_test_flag64(peer, IAX_DYNAMIC)); ast_data_add_bool(data_peer, "dynamic", ast_test_flag64(peer, IAX_DYNAMIC));
encmethods_to_str(peer->encmethods, encmethods); encmethods_to_str(peer->encmethods, &encmethods);
ast_data_add_str(data_peer, "encryption", peer->encmethods ? ast_str_buffer(encmethods) : "no"); ast_data_add_str(data_peer, "encryption", peer->encmethods ? ast_str_buffer(encmethods) : "no");
peer_unref(peer); peer_unref(peer);

View File

@@ -793,6 +793,12 @@ char *__ast_str_helper2(struct ast_str **buf, ssize_t max_len,
* ... * ...
* } * }
* \endcode * \endcode
*
* \note Care should be taken when using this function. The function can
* result in reallocating the ast_str. If a pointer to the ast_str is passed
* by value to a function that calls ast_str_set_va(), then the original ast_str
* pointer may be invalidated due to a reallocation.
*
*/ */
AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap), AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap),
{ {
@@ -805,6 +811,11 @@ AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_set_va(struct a
* *
* Same as ast_str_set_va(), but append to the current content. * Same as ast_str_set_va(), but append to the current content.
* *
* \note Care should be taken when using this function. The function can
* result in reallocating the ast_str. If a pointer to the ast_str is passed
* by value to a function that calls ast_str_append_va(), then the original ast_str
* pointer may be invalidated due to a reallocation.
*
* \param buf, max_len, fmt, ap * \param buf, max_len, fmt, ap
*/ */
AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_append_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap), AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_append_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap),
@@ -844,6 +855,11 @@ AST_INLINE_API(char *ast_str_append_escapecommas(struct ast_str **buf, ssize_t m
/*! /*!
* \brief Set a dynamic string using variable arguments * \brief Set a dynamic string using variable arguments
* *
* \note Care should be taken when using this function. The function can
* result in reallocating the ast_str. If a pointer to the ast_str is passed
* by value to a function that calls ast_str_set(), then the original ast_str
* pointer may be invalidated due to a reallocation.
*
* \param buf This is the address of a pointer to a struct ast_str which should * \param buf This is the address of a pointer to a struct ast_str which should
* have been retrieved using ast_str_thread_get. It will need to * have been retrieved using ast_str_thread_get. It will need to
* be updated in the case that the buffer has to be reallocated to * be updated in the case that the buffer has to be reallocated to
@@ -876,6 +892,11 @@ int __attribute__((format(printf, 3, 4))) ast_str_set(
/*! /*!
* \brief Append to a thread local dynamic string * \brief Append to a thread local dynamic string
* *
* \note Care should be taken when using this function. The function can
* result in reallocating the ast_str. If a pointer to the ast_str is passed
* by value to a function that calls ast_str_append(), then the original ast_str
* pointer may be invalidated due to a reallocation.
*
* The arguments, return values, and usage of this function are the same as * The arguments, return values, and usage of this function are the same as
* ast_str_set(), but the new data is appended to the current value. * ast_str_set(), but the new data is appended to the current value.
*/ */

View File

@@ -3446,7 +3446,7 @@ struct ast_cc_monitor *ast_cc_get_monitor_by_recall_core_id(const int core_id, c
* \param dialstring A new dialstring to add * \param dialstring A new dialstring to add
* \retval void * \retval void
*/ */
static void cc_unique_append(struct ast_str *str, const char *dialstring) static void cc_unique_append(struct ast_str **str, const char *dialstring)
{ {
char dialstring_search[AST_CHANNEL_NAME]; char dialstring_search[AST_CHANNEL_NAME];
@@ -3455,10 +3455,10 @@ static void cc_unique_append(struct ast_str *str, const char *dialstring)
return; return;
} }
snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&'); snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
if (strstr(ast_str_buffer(str), dialstring_search)) { if (strstr(ast_str_buffer(*str), dialstring_search)) {
return; return;
} }
ast_str_append(&str, 0, "%s", dialstring_search); ast_str_append(str, 0, "%s", dialstring_search);
} }
/*! /*!
@@ -3476,7 +3476,7 @@ static void cc_unique_append(struct ast_str *str, const char *dialstring)
* \param str Where we will store CC_INTERFACES * \param str Where we will store CC_INTERFACES
* \retval void * \retval void
*/ */
static void build_cc_interfaces_chanvar(struct ast_cc_monitor *starting_point, struct ast_str *str) static void build_cc_interfaces_chanvar(struct ast_cc_monitor *starting_point, struct ast_str **str)
{ {
struct extension_monitor_pvt *extension_pvt; struct extension_monitor_pvt *extension_pvt;
struct extension_child_dialstring *child_dialstring; struct extension_child_dialstring *child_dialstring;
@@ -3485,7 +3485,7 @@ static void build_cc_interfaces_chanvar(struct ast_cc_monitor *starting_point, s
size_t length; size_t length;
/* Init to an empty string. */ /* Init to an empty string. */
ast_str_truncate(str, 0); ast_str_truncate(*str, 0);
/* First we need to take all of the is_valid child_dialstrings from /* First we need to take all of the is_valid child_dialstrings from
* the extension monitor we found and add them to the CC_INTERFACES * the extension monitor we found and add them to the CC_INTERFACES
@@ -3508,9 +3508,9 @@ static void build_cc_interfaces_chanvar(struct ast_cc_monitor *starting_point, s
/* str will have an extra '&' tacked onto the end of it, so we need /* str will have an extra '&' tacked onto the end of it, so we need
* to get rid of that. * to get rid of that.
*/ */
length = ast_str_strlen(str); length = ast_str_strlen(*str);
if (length) { if (length) {
ast_str_truncate(str, length - 1); ast_str_truncate(*str, length - 1);
} }
if (length <= 1) { if (length <= 1) {
/* Nothing to recall? This should not happen. */ /* Nothing to recall? This should not happen. */
@@ -3545,7 +3545,7 @@ int ast_cc_agent_set_interfaces_chanvar(struct ast_channel *chan)
AST_LIST_LOCK(interface_tree); AST_LIST_LOCK(interface_tree);
monitor = AST_LIST_FIRST(interface_tree); monitor = AST_LIST_FIRST(interface_tree);
build_cc_interfaces_chanvar(monitor, str); build_cc_interfaces_chanvar(monitor, &str);
AST_LIST_UNLOCK(interface_tree); AST_LIST_UNLOCK(interface_tree);
pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str)); pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));
@@ -3597,7 +3597,7 @@ int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char * const e
return -1; return -1;
} }
build_cc_interfaces_chanvar(monitor_iter, str); build_cc_interfaces_chanvar(monitor_iter, &str);
AST_LIST_UNLOCK(interface_tree); AST_LIST_UNLOCK(interface_tree);
pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str)); pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(str));