Coordinated Disclosure Timeline

Summary

An unprivileged local attacker can trigger a use-after-free vulnerability in accountsservice by sending a D-Bus message to the accounts-daemon process.

Product

accountsservice

Tested Version

22.08.8-1ubuntu7

The bug is easier to observe on Ubuntu 23.04 than on Ubuntu 22.04 LTS, but it is present on both.

Details

Use-after-free when throw_error is called (GHSL-2023-139)

After receiving a D-Bus method call, a D-Bus server is expected to send either a METHOD_RETURN or a ERROR message back to the client, but not both. This is done incorrectly in several places in accountsservice. For example, in user_change_language_authorized_cb:

static void
user_change_language_authorized_cb (Daemon                *daemon,
                                    User                  *user,
                                    GDBusMethodInvocation *context,
                                    gpointer               data)

{
        const gchar *language = data;

        if (!user_HOME_available (user)) {

                /* SetLanguage was probably called from a login greeter,
                   and HOME not mounted and/or not decrypted.
                   Hence don't save anything, or else accountsservice
                   and ~/.pam_environment would become out of sync. */
                throw_error (context, ERROR_FAILED, "not access to HOME yet so language not saved");  <===== 1
                goto out;
        }

        <snip>

out:
        accounts_user_complete_set_language (ACCOUNTS_USER (user), context);  <===== 2
}

If user_HOME_available returns an error, then throw_error is called at 1 to send an ERROR message, but a regular METHOD_RETURN is also sent at 2. This is incorrect D-Bus protocol, but the more serious problem is that it causes a use-after-free because both throw_error and accounts_user_complete_set_language decrease the reference count on context. In other words, context is freed by throw_error and a UAF occurs in accounts_user_complete_set_language.

An attacker can trigger the bug above by causing user_HOME_available to fail, which they can do by deleting all the files from their home directory. But there are other incorrect uses of throw_error in user.c which are less inconvenient to trigger. For example, this command triggers a call to throw_error in user_update_environment due to the invalid characters in the string:

dbus-send --system --print-reply --dest=org.freedesktop.Accounts /org/freedesktop/Accounts/User`id -u` org.freedesktop.Accounts.User.SetLanguage string:'**'

On Ubuntu 23.04, the above command causes accounts-daemon to crash with a SIGSEGV. But on Ubuntu 22.04 LTS it doesn’t cause any visible harm. The difference is due to a recent change in GLib’s memory allocation: older versions of GLib used the “slice” allocator, but newer version uses the system allocator. The system allocator trashes the memory when it’s freed in a way that causes the use-after-free to trigger a SIGSEGV, whereas the “slice” allocator trashes the memory in a way that causes the UAF to go unnoticed.

Impact

Exploitation is likely to be difficult, but this bug could potentially enable a local unprivileged attacker to gain root privileges.

CVE

Credit

This issue was discovered and reported by GHSL team member @kevinbackhouse (Kevin Backhouse).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2023-139 in any communication regarding this issue.