Skip to content

Commit

Permalink
bluetooth: host: conn: Check if *conn is not NULL
Browse files Browse the repository at this point in the history
This commit adds a warning and a Kconfig option to `bt_conn_le_create`
and `bt_conn_le_create_synced` functions which are meant to warn a user
of a potential leakage of an active connection object.

This change is implemented due to frequent incorrect use of the
connection pointer where a pointer to an existing connection object
is overwritten by `bt_conn_le_create` and `bt_conn_le_create_synced`
functions which in turns leads to sporadic critical bugs. See
zephyrproject-rtos#78284 (comment)
for more details.

The Kconfig option is introduced instead of always returning the error
to not affect current implementations. However, it is recommended to
keep this option enabled to avoid potential bugs.

Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
  • Loading branch information
PavelVPV committed Oct 17, 2024
1 parent 1726443 commit 8b77d3c
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 2 deletions.
8 changes: 8 additions & 0 deletions doc/connectivity/bluetooth/api/connection_mgmt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ longer period of time, since this ensures that the object remains valid
:c:func:`bt_conn_unref` API is to be used when releasing a reference
to a connection.

A common mistake is to forget unreleasing a reference to a connection
object created by functions :c:func:`bt_conn_le_create` and
:c:func:`bt_conn_le_create_synced`. To protect against this, use the
:kconfig:option:`CONFIG_BT_CONN_CHECK_NULL_BEFORE_CREATE` Kconfig option,
which forces these functions return an error if the connection pointer
passed to them is not NULL. This helps to spot such issues and avoid
sporadic bugs caused by not releasing the connection object.

An application may track connections by registering a
:c:struct:`bt_conn_cb` struct using the :c:func:`bt_conn_cb_register`
or :c:macro:`BT_CONN_CB_DEFINE` APIs. This struct lets the application
Expand Down
7 changes: 7 additions & 0 deletions doc/releases/release-notes-4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ Bluetooth
* Added API :c:func:`bt_gatt_get_uatt_mtu` to get current Unenhanced ATT MTU of a given
connection (experimental).

* Added a warning to :c:func:`bt_conn_le_create` and :c:func:`bt_conn_le_create_synced` if
the connection pointer passed as an argument is not NULL.

* Added Kconfig option :kconfig:option:`CONFIG_BT_CONN_CHECK_NULL_BEFORE_CREATE` to enforce
:c:func:`bt_conn_le_create` and :c:func:`bt_conn_le_create_synced` return an error if the
connection pointer passed as an argument is not NULL.

* HCI Drivers

Boards & SoC Support
Expand Down
8 changes: 6 additions & 2 deletions include/zephyr/bluetooth/conn.h
Original file line number Diff line number Diff line change
Expand Up @@ -1320,7 +1320,9 @@ struct bt_conn_le_create_param {
* Allows initiate new LE link to remote peer using its address.
*
* The caller gets a new reference to the connection object which must be
* released with bt_conn_unref() once done using the object.
* released with bt_conn_unref() once done using the object. If
* @kconfig{CONFIG_BT_CONN_CHECK_NULL_BEFORE_CREATE} is enabled, this function
* will return -EINVAL if dereferenced @p conn is not NULL.
*
* This uses the General Connection Establishment procedure.
*
Expand Down Expand Up @@ -1359,7 +1361,9 @@ struct bt_conn_le_create_synced_param {
* with Responses (PAwR) train.
*
* The caller gets a new reference to the connection object which must be
* released with bt_conn_unref() once done using the object.
* released with bt_conn_unref() once done using the object. If
* @kconfig{CONFIG_BT_CONN_CHECK_NULL_BEFORE_CREATE} is enabled, this function
* will return -EINVAL if dereferenced @p conn is not NULL.
*
* This uses the Periodic Advertising Connection Procedure.
*
Expand Down
11 changes: 11 additions & 0 deletions subsys/bluetooth/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,17 @@ config BT_CONN_PARAM_ANY
min and max connection intervals in order to verify whether the
desired parameters have been established in the connection.

config BT_CONN_CHECK_NULL_BEFORE_CREATE
bool "Check if *conn is NULL when creating a connection"
help
Enable this option to ensure that bt_conn_le_create and
bt_conn_le_create_synced return an error if *conn is not initialized
to NULL. This option is recommended to use to catch programming
errors where the application reuses the connection pointer of an
active connection object without dereferencing it. Without
dereferencing, the connection object stays alive which can lead to an
unpredictable behavior.

config BT_USER_PHY_UPDATE
bool "User control of PHY Update Procedure"
depends on BT_PHY_UPDATE
Expand Down
34 changes: 34 additions & 0 deletions subsys/bluetooth/host/conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -3674,6 +3674,23 @@ int bt_conn_le_create(const bt_addr_le_t *peer, const struct bt_conn_le_create_p
struct bt_conn *conn;
int err;

CHECKIF(ret_conn == NULL) {
return -EINVAL;
}

CHECKIF(*ret_conn != NULL) {
/* This rule helps application developers prevent leaks of connection references. If
* a bt_conn variable is not null, it presumably holds a reference and must not be
* overwritten. To avoid this warning, initialize the variables to null, and set
* them to null when moving the reference.
*/
LOG_WRN("*conn should be unreferenced and initialized to NULL");

if (IS_ENABLED(CONFIG_BT_CONN_CHECK_NULL_BEFORE_CREATE)) {
return -EINVAL;
}
}

err = conn_le_create_common_checks(peer, conn_param);
if (err) {
return err;
Expand Down Expand Up @@ -3733,6 +3750,23 @@ int bt_conn_le_create_synced(const struct bt_le_ext_adv *adv,
struct bt_conn *conn;
int err;

CHECKIF(ret_conn == NULL) {
return -EINVAL;
}

CHECKIF(*ret_conn != NULL) {
/* This rule helps application developers prevent leaks of connection references. If
* a bt_conn variable is not null, it presumably holds a reference and must not be
* overwritten. To avoid this warning, initialize the variables to null, and set
* them to null when moving the reference.
*/
LOG_WRN("*conn should be unreferenced and initialized to NULL");

if (IS_ENABLED(CONFIG_BT_CONN_CHECK_NULL_BEFORE_CREATE)) {
return -EINVAL;
}
}

err = conn_le_create_common_checks(synced_param->peer, conn_param);
if (err) {
return err;
Expand Down

0 comments on commit 8b77d3c

Please sign in to comment.