google / syzkaller

syzkaller is an unsupervised coverage-guided kernel fuzzer
Apache License 2.0
5.29k stars 1.2k forks source link

executor: provoke double-fetch bugs #355

Open dvyukov opened 7 years ago

dvyukov commented 7 years ago

Double-fetch (aka TOCTOU) is a class of bugs where kernel code executes copy_from_user twice for the same user region and expects that contents do not change. See: https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-wang.pdf https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/42189.pdf The first work has identified 5 double-fetch bugs in Linux kernel.

We may consider to provoke them more actively somehow by changing the data in another thread. And/or detect potential TOCTOU cases. E.g. instrument copy_from_user and memorize copied regions in task context and report when a syscall fetches the same range more than once.

dvyukov commented 6 years ago

FTR, a bunch of recent double-fetch bugs in Linux kernel:

commit f16b613ca8b3e4960cdc5575e9b8e1dbdd7d54d5
Author: Wenwen Wang
Date:   Fri May 18 14:55:35 2018 -0500

    crypto: chtls - fix a missing-check bug

    In do_chtls_setsockopt(), the tls crypto info is first copied from the
    poiner 'optval' in userspace and saved to 'tmp_crypto_info'. Then the
    'version' of the crypto info is checked. If the version is not as expected,
    i.e., TLS_1_2_VERSION, error code -ENOTSUPP is returned to indicate that
    the provided crypto info is not supported yet. Then, the 'cipher_type'
    field of the 'tmp_crypto_info' is also checked to see if it is
    TLS_CIPHER_AES_GCM_128. If it is, the whole struct of
    tls12_crypto_info_aes_gcm_128 is copied from the pointer 'optval' and then
    the function chtls_setkey() is invoked to set the key.

    Given that the 'optval' pointer resides in userspace, a malicious userspace
    process can race to change the data pointed by 'optval' between the two
    copies. For example, a user can provide a crypto info with TLS_1_2_VERSION
    and TLS_CIPHER_AES_GCM_128. After the first copy, the user can modify the
    'version' and the 'cipher_type' fields to any versions and/or cipher types
    that are not allowed. This way, the user can bypass the checks, inject
    bad data to the kernel, cause chtls_setkey() to set a wrong key or other
    issues.

    This patch reuses the data copied in the first try so as to ensure these
    checks will not be bypassed.

commit 6009d1fe6ba3bb2dab55921da60465329cc1cd89
Author: Wenwen Wang
Date:   Mon May 21 01:58:07 2018 -0500

    isdn: eicon: fix a missing-check bug

    In divasmain.c, the function divas_write() firstly invokes the function
    diva_xdi_open_adapter() to open the adapter that matches with the adapter
    number provided by the user, and then invokes the function diva_xdi_write()
    to perform the write operation using the matched adapter. The two functions
    diva_xdi_open_adapter() and diva_xdi_write() are located in diva.c.

    In diva_xdi_open_adapter(), the user command is copied to the object 'msg'
    from the userspace pointer 'src' through the function pointer 'cp_fn',
    which eventually calls copy_from_user() to do the copy. Then, the adapter
    number 'msg.adapter' is used to find out a matched adapter from the
    'adapter_queue'. A matched adapter will be returned if it is found.
    Otherwise, NULL is returned to indicate the failure of the verification on
    the adapter number.

    As mentioned above, if a matched adapter is returned, the function
    diva_xdi_write() is invoked to perform the write operation. In this
    function, the user command is copied once again from the userspace pointer
    'src', which is the same as the 'src' pointer in diva_xdi_open_adapter() as
    both of them are from the 'buf' pointer in divas_write(). Similarly, the
    copy is achieved through the function pointer 'cp_fn', which finally calls
    copy_from_user(). After the successful copy, the corresponding command
    processing handler of the matched adapter is invoked to perform the write
    operation.

    It is obvious that there are two copies here from userspace, one is in
    diva_xdi_open_adapter(), and one is in diva_xdi_write(). Plus, both of
    these two copies share the same source userspace pointer, i.e., the 'buf'
    pointer in divas_write(). Given that a malicious userspace process can race
    to change the content pointed by the 'buf' pointer, this can pose potential
    security issues. For example, in the first copy, the user provides a valid
    adapter number to pass the verification process and a valid adapter can be
    found. Then the user can modify the adapter number to an invalid number.
    This way, the user can bypass the verification process of the adapter
    number and inject inconsistent data.

    This patch reuses the data copied in
    diva_xdi_open_adapter() and passes it to diva_xdi_write(). This way, the
    above issues can be avoided.

commit bd23a7269834dc7c1f93e83535d16ebc44b75eba
Author: Wenwen Wang
Date:   Tue May 8 08:50:28 2018 -0500

    virt: vbox: Only copy_from_user the request-header once

    In vbg_misc_device_ioctl(), the header of the ioctl argument is copied from
    the userspace pointer 'arg' and saved to the kernel object 'hdr'. Then the
    'version', 'size_in', and 'size_out' fields of 'hdr' are verified.

    Before this commit, after the checks a buffer for the entire request would
    be allocated and then all data including the verified header would be
    copied from the userspace 'arg' pointer again.

    Given that the 'arg' pointer resides in userspace, a malicious userspace
    process can race to change the data pointed to by 'arg' between the two
    copies. By doing so, the user can bypass the verifications on the ioctl
    argument.

    This commit fixes this by using the already checked copy of the header
    to fill the header part of the allocated buffer and only copying the
    remainder of the data from userspace.

commit 3f12888dfae2a48741c4caa9214885b3aaf350f9
Author: Wenwen Wang
Date:   Sat May 5 13:38:03 2018 -0500

    ALSA: control: fix a redundant-copy issue

    In snd_ctl_elem_add_compat(), the fields of the struct 'data' need to be
    copied from the corresponding fields of the struct 'data32' in userspace.
    This is achieved by invoking copy_from_user() and get_user() functions. The
    problem here is that the 'type' field is copied twice. One is by
    copy_from_user() and one is by get_user(). Given that the 'type' field is
    not used between the two copies, the second copy is *completely* redundant
    and should be removed for better performance and cleanup. Also, these two
    copies can cause inconsistent data: as the struct 'data32' resides in
    userspace and a malicious userspace process can race to change the 'type'
    field between the two copies to cause inconsistent data. Depending on how
    the data is used in the future, such an inconsistency may cause potential
    security risks.

    For above reasons, we should take out the second copy.

commit dc487321b1e6ab27f545fd8826ce3f76b01b63c2
Author: Wenwen Wang
Date:   Mon Apr 30 17:56:10 2018 -0500

    staging: lustre: llite: fix potential missing-check bug when copying lumv

    In ll_dir_ioctl(), the object lumv3 is firstly copied from the user space
    using Its address, i.e., lumv1 = &lumv3. If the lmm_magic field of lumv3 is
    LOV_USER_MAGIC_V3, lumv3 will be modified by the second copy from the user
    space. The second copy is necessary, because the two versions (i.e.,
    lov_user_md_v1 and lov_user_md_v3) have different data formats and lengths.
    However, given that the user data resides in the user space, a malicious
    user-space process can race to change the data between the two copies. By
    doing so, the attacker can provide a data with an inconsistent version,
    e.g., v1 version + v3 data. This can lead to logical errors in the
    following execution in ll_dir_setstripe(), which performs different actions
    according to the version specified by the field lmm_magic.

    This patch rechecks the version field lmm_magic in the second copy.  If the
    version is not as expected, i.e., LOV_USER_MAGIC_V3, an error code will be
    returned: -EINVAL.

commit d656fe49e33df48ee6bc19e871f5862f49895c9e
Author: Wenwen Wang
Date:   Mon Apr 30 12:31:13 2018 -0500

    ethtool: fix a potential missing-check bug

    In ethtool_get_rxnfc(), the object "info" is firstly copied from
    user-space. If the FLOW_RSS flag is set in the member field flow_type of
    "info" (and cmd is ETHTOOL_GRXFH), info needs to be copied again from
    user-space because FLOW_RSS is newer and has new definition, as mentioned
    in the comment. However, given that the user data resides in user-space, a
    malicious user can race to change the data after the first copy. By doing
    so, the user can inject inconsistent data. For example, in the second
    copy, the FLOW_RSS flag could be cleared in the field flow_type of "info".
    In the following execution, "info" will be used in the function
    ops->get_rxnfc(). Such inconsistent data can potentially lead to unexpected
    information leakage since ops->get_rxnfc() will prepare various types of
    data according to flow_type, and the prepared data will be eventually
    copied to user-space. This inconsistent data may also cause undefined
    behaviors based on how ops->get_rxnfc() is implemented.

    This patch simply re-verifies the flow_type field of "info" after the
    second copy. If the value is not as expected, an error code will be
    returned.
dvyukov commented 4 years ago

FTR a TOCTOU vulnerability in FreeBSD: https://www.freebsd.org/security/advisories/FreeBSD-SA-20:23.sendmsg.asc

dvyukov commented 3 years ago

Here is the corresponding kernel change: https://github.com/Merna177/linux/pull/1