Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/hci-socket/hci.js
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,12 @@ Hci.prototype.processLeAdvertisingReport = function (numReports, data) {
Hci.prototype.processLeExtendedAdvertisingReport = function (numReports, data) {
try {
for (let i = 0; i < numReports; i++) {
if (data.length < 24) {
console.warn(
`processLeExtendedAdvertisingReport: Caught illegal packet (too short: ${data.length} < 24)`
);
break;
}
const type = data.readUInt16LE(0);
const addressType = data.readUInt8(2) === 0x01 ? 'random' : 'public';
const address = data
Expand All @@ -1258,6 +1264,12 @@ Hci.prototype.processLeExtendedAdvertisingReport = function (numReports, data) {
.reverse()
.join(':');
const eirLength = data.readUInt8(23);
if (data.length < 24 + eirLength) {
console.warn(
`processLeExtendedAdvertisingReport: Caught illegal packet (eir length ${eirLength} exceeds remaining ${data.length - 24})`
);
break;
}
const eir = data.slice(24);

debug(`\t\t\ttype = ${type}`);
Expand Down
51 changes: 47 additions & 4 deletions test/lib/hci-socket/hci.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1891,8 +1891,12 @@ describe('hci-socket hci', () => {
describe('processLeExtendedAdvertisingReport', () => {
it('should emit without error', () => {
const count = 2;
const data1 = Buffer.from([0, 1, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0]);
const data2 = Buffer.from([1, 0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 4, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]);
const eir1 = Buffer.from([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]);
const header1 = Buffer.from([0, 1, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, eir1.length]);
const data1 = Buffer.concat([header1, eir1]);
const eir2 = Buffer.from([0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27]);
const header2 = Buffer.from([1, 0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 4, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, eir2.length]);
const data2 = Buffer.concat([header2, eir2]);
const data = Buffer.concat([data1, data2]);
const callback = sinon.spy();

Expand All @@ -1904,7 +1908,9 @@ describe('hci-socket hci', () => {

it('should emit only once with random address', () => {
const count = 1;
const data = Buffer.from([0, 1, 1, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]);
const eir = Buffer.from([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]);
const header = Buffer.from([0, 1, 1, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, eir.length]);
const data = Buffer.concat([header, eir]);
const callback = sinon.spy();

hci.on('leExtendedAdvertisingReport', callback);
Expand All @@ -1915,7 +1921,9 @@ describe('hci-socket hci', () => {

it('should emit only once with public address', () => {
const count = 1;
const data = Buffer.from([0, 1, 2, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]);
const eir = Buffer.from([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]);
const header = Buffer.from([0, 1, 2, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, eir.length]);
const data = Buffer.concat([header, eir]);
const callback = sinon.spy();

hci.on('leExtendedAdvertisingReport', callback);
Expand All @@ -1937,6 +1945,41 @@ describe('hci-socket hci', () => {
assert.notCalled(callback);
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('illegal packet'));
});

it('should ignore too-short extended report without throwing', () => {
const count = 1;
const data = Buffer.alloc(10);
const callback = sinon.spy();

const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});

hci.on('leExtendedAdvertisingReport', callback);
hci.processLeExtendedAdvertisingReport(count, data);

assert.notCalled(callback);
expect(consoleSpy.mock.calls.some((call) => String(call[0]).includes('too short'))).toBe(true);
consoleSpy.mockRestore();
});

it('should ignore extended report with oversized eir length', () => {
const count = 1;
const data = Buffer.from([
0, 1, 2, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
200, // eirLength larger than remaining bytes
0x01, 0x02, 0x03,
]);
const callback = sinon.spy();

const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});

hci.on('leExtendedAdvertisingReport', callback);
hci.processLeExtendedAdvertisingReport(count, data);

assert.notCalled(callback);
expect(consoleSpy.mock.calls.some((call) => String(call[0]).includes('eir length'))).toBe(true);
consoleSpy.mockRestore();
});
});

it('processLeConnUpdateComplete', () => {
Expand Down
Loading