Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] iOS: crash caused by 1-byte advertisements #1022

Merged
merged 1 commit into from
Oct 17, 2024

Conversation

cervm
Copy link
Contributor

@cervm cervm commented Oct 17, 2024

Our app was crashing when a nearby device advertised with only 1 byte of data. This was due to the assumption that the first two bytes always contained the manufacturer ID. This fix prevents going to a negative index causing the app to crash completely.

Screenshot 2024-10-17 at 13 18 30

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
The app was crashing when a nearby device advertised with only 1 byte of data. This was due to the assumption that the first two bytes always contained the manufacturer ID. This prevents going to a negative index.
@chipweinberger chipweinberger merged commit ae47a23 into chipweinberger:master Oct 17, 2024
@chipweinberger
Copy link
Owner

thanks

@chipweinberger
Copy link
Owner

chipweinberger commented Oct 17, 2024

fixed in 1.33.5

@MrCsabaToth
Copy link
Contributor

What device was that? I may check the Android port if I have time for this case.

@chipweinberger
Copy link
Owner

chipweinberger commented Oct 28, 2024

I don't see a way it could break.

lets say bytes.length is 2

fieldLen is 1

and n is 1

then this check will still work // Ensuring we don't go past the bytes array

    Map<Integer, byte[]> getManufacturerSpecificData(ScanRecord adv) {
        byte[] bytes = adv.getBytes();
        Map<Integer, byte[]> manufacturerDataMap = new HashMap<>();
        int n = 0;
        while (n < bytes.length) {

            // layout:
            // n[0] = fieldlen
            // n[1] = datatype (MSD)
            // n[2] = manufacturerId (low)
            // n[3] = manufacturerId (high)
            // n[4] = data...
            int fieldLen = bytes[n] & 0xFF;

            // no more or malformed data
            if (fieldLen <= 0) {
                break;
            }

            // Ensuring we don't go past the bytes array
            if (n + fieldLen >= bytes.length) {
                break;
            }

            int dataType = bytes[n + 1] & 0xFF;

            // Manufacturer Specific Data magic number
            // At least 3 bytes: 2 for manufacturer ID & 1 for dataType
            if (dataType == 0xFF && fieldLen >= 3) {

                // Manufacturer Id
                int high = (bytes[n + 3] & 0xFF) << 8;
                int low = (bytes[n + 2] & 0xFF);
                int manufacturerId = high | low;

                // the length of the msd data,
                // excluding manufacturerId & dataType
                int msdLen = fieldLen - 3;

                // ptr to msd data
                // excluding manufacturerId & dataType
                int msdPtr = n + 4;

                // add to map
                if (manufacturerDataMap.containsKey(manufacturerId)) {
                    // If the manufacturer ID already exists, append the new data to the existing list
                    byte[] existingData = manufacturerDataMap.get(manufacturerId);
                    byte[] mergedData = new byte[existingData.length + msdLen];
                    // Merge arrays
                    System.arraycopy(existingData, 0, mergedData, 0, existingData.length);
                    System.arraycopy(bytes, msdPtr, mergedData, existingData.length, msdLen);
                    manufacturerDataMap.put(manufacturerId, mergedData);
                } else {
                    // Otherwise, put the new manufacturer ID and its data into the map
                    byte[] data = new byte[msdLen];
                    // Starting from n+4 because manufacturerId occupies n+2 and n+3
                    System.arraycopy(bytes, msdPtr, data, 0, data.length);
                    manufacturerDataMap.put(manufacturerId, data);
                }
            }

            n += fieldLen + 1;
        }

        return manufacturerDataMap;
    }
    ```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants