Page MenuHomeFreeBSD

bluetooth: Default to discoverable off
ClosedPublic

Authored by cem on Oct 30 2017, 4:31 AM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Mar 20, 12:07 PM
Unknown Object (File)
Wed, Mar 20, 12:07 PM
Unknown Object (File)
Wed, Mar 20, 12:07 PM
Unknown Object (File)
Thu, Mar 7, 3:05 PM
Unknown Object (File)
Feb 27 2024, 12:20 AM
Unknown Object (File)
Feb 26 2024, 2:54 PM
Unknown Object (File)
Feb 26 2024, 7:14 AM
Unknown Object (File)
Jan 10 2024, 2:23 PM

Details

Summary

Try to not expose bluetooth devices to external devices unless the user
explicitly configures it, like any other radio/network device. Bluetooth
has a long history of security problems and it is probably best to keep it
disabled if not needed.

Users who do use the bluetooth device should enable "discoverable" in
bluetooth.device.conf(5) after this change.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

This revision is now accepted and ready to land.Oct 30 2017, 4:35 AM
allanjude added a subscriber: allanjude.

bluetooth should not be unconditional.

Thank you.

Move setting under "Bluetooth" section of default/rc.conf

This revision now requires review to proceed.Oct 30 2017, 4:40 AM
This revision is now accepted and ready to land.Oct 30 2017, 4:50 AM
etc/defaults/rc.conf
422 ↗(On Diff #34445)

can you please explain why is this needed? original idea was to run /etc/rc.d/bluetooth from devd.conf in response to arrival of bluetooth device.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

We shouldn't bring wireless interfaces online unless the user explicitly enables them in rc.conf.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

I'm fine if bluetooth is off by default.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

agreed, however, this was not my point. if someone were to set bluetooth_enable to "YES" in rc.conf wouldn't this cause /etc/rc.d/bluetooth executed by default on every boot? even if no bluetooth devices are present. and if they are, wouldn't /etc/rc.d/bluetooth be executed twice?

etc/defaults/rc.conf
422 ↗(On Diff #34445)

It should be a no-op without a device argument, right? Currently we get /etc/rc.d/bluetooth: ERROR: Unsupported device: but that can be fixed.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

i think it would be better to make 'start' and 'stop' commands always no-op in /etc/rc.d/bluetooth. in the same time, add new commands, i.e. 'activate' and 'deactivate' that would require device name. however, i can see how it can create a lot of confusion and changes in documentation.

making 'start' and 'stop' be no-op when device name is missing is an option, however, it may be confusing for someone to see 'start' and 'stop' doing nothing and producing no warning / error about required device name.

i have no strong opinion here.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

actually, can we use / check different (from bluetooth_enable) variable and leave rcvar alone to avoid clash ?

etc/defaults/rc.conf
422 ↗(On Diff #34445)

I don't really want to change start/stop commands. That seems reasonable enough to me, and matches typical network interfaces.

We can warn the user to add a device name when rc_quiet isn't set.

Why use a different variable / what clash?

By the way, a bigger problem seems to be that just loading ng_ubt seems to bring up the interface. This is pretty surprising to me. hccontrol -n ubt0hci reset seems to disable it, but I don't think that will work without the netgraph scaffolding.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

that's fine with me. start/stop can stay as they are now. may be add warning about missing argument or something more useful than what we have now.

i'm fine with using "checkyesno bluetooth_enable" as long as rcvar is back to empty value.

loading ng_ubt will cause device attach (if device is preset), this will cause devd notification and, finally, device will be brought up by call to /etc/rc.d/bluetooth. that's by design. i, personally, think that this is not a huge deal. user has to enable and start extra services to make device actually do something. otherwise its just an active radio that can respond to baseband connections requests and l2ping's. if this is a concern, one can change "connectable" and "discoverable" parameters in default/bluetooth.device.conf.

hci reset is a big hammer. depending on the device, it may or may not come back after reset is issued. especially if device requires firmware download. i've seen devices where reset simply kills it. otherwise there is nothing special about hci reset, and, i dont think its intended to disable device.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

i'm fine with using "checkyesno bluetooth_enable" as long as rcvar is back to empty value.

I'm fine with that I guess, but what difference does it make? rcvar seems to be the convention.

loading ng_ubt will cause device attach (if device is preset), this will cause devd notification and, finally, device will be brought up by call to /etc/rc.d/bluetooth.

Yes, however, when I disable bluetooth via rcvar, the /etc/rc.d/bluetooth quietstart ubt0 is a no-op. After just kldload, ubt0 still begins broadcasting! I don't think that's good.

i, personally, think that this is not a huge deal. user has to enable and start extra services to make device actually do something. otherwise its just an active radio that can respond to baseband connections requests and l2ping's. if this is a concern

Yes, I think that's a concern.

one can change "connectable" and "discoverable" parameters in default/bluetooth.device.conf.

Perhaps that's the actual change we should make here? Just switch those defaults to off.

Is there a better way to disable the device? Can we completely disable the radio? Thanks!

etc/defaults/rc.conf
422 ↗(On Diff #34445)

rcvar is a "special" variable. /etc/rc.d/bluetooth is/was not expected to be run during normal boot/shutdown rc.d sequence. it is only run in response to notifications from devd, i.e. device arrival and departure. for this reason, rcvar is/was empty. there are other examples where rc.d scripts would set rcvar to empty value.

i'm sorry, but i don't understand your comment about "broadcasting". nothing is being broadcasted. bluetooth device are not NICs. bluetooth devices are more like external modems. all "start" command does it making sure device is setup and ready to be communicated with. traditional NIC would have one monolithic driver that does everything. bluetooth device requires support from multiple kernel modules because it uses well defined message based interface.

to summarize: i think we should leave rcvar empty as it was. i, personally, don't see huge purpose in having bluetooth_enable knob. preventing plumbing of netgraph nodes is not a good thing imo. i would assume (and please correct me if i'm wrong) that by "broadcasting" you really mean "discoverable by default". as i have mentioned above, setting "discoverable" to NO by default would prevent it.

in other words, i would suggest to undo all the changes and simply set "discoverable" to NO by default. this would be identical to how all other OSes do it, i.e. device is configured and ready to use, but, by default, will not answer inquiry scan (i.e. will not "broadcast").

etc/defaults/rc.conf
422 ↗(On Diff #34445)

i'm sorry, but i don't understand your comment about "broadcasting". nothing is being broadcasted.

Clearly that is not true. My phone, which is not associated with the host bluetooth, can see the bluetooth device "local name." That means a radio is transmitting that information, and additionally that it is broadcast to anyone listening.

i would assume (and please correct me if i'm wrong) that by "broadcasting" you really mean "discoverable by default". as i have mentioned above, setting "discoverable" to NO by default would prevent it.

I mean, not discoverable is a step in the right direction, but really we want to be able to disable the radio entirely. By default.

I will go ahead and make that change.

etc/defaults/rc.conf
422 ↗(On Diff #34445)

please set "discoverable" to "NO". again, nothing is being "broadcasted". your phone is performing "inquiry scan", and, remote device responds with its information. setting "discoverable" to "NO" would cause device to NOT respond to "inquiry scan" and your phone will not "see" it.

Change bluetooth defaults to non-discoverable, non-connectable

Not populating the netgraph nodes doesn't actually prevent the radio from
coming online. So there is no point in bluetooth_enable.

This revision now requires review to proceed.Oct 31 2017, 6:13 PM
cem retitled this revision from Add rcvar for bluetooth service to bluetooth: Default to not discoverable nor connectable.Oct 31 2017, 6:14 PM
cem edited the summary of this revision. (Show Details)
etc/defaults/rc.conf
422 ↗(On Diff #34445)

I think we're stumbling over a terminology problem. A radio must broadcast to "respond with its information." That's just how radios work.

Can we guarantee nothing else will cause the device to transmit if discoverable is NO/0? That's really the goal.

etc/defaults/bluetooth.device.conf
58 ↗(On Diff #34553)

please don't set this to NO. it will break things for already working setups.

i must say, i'm not entirely certain about the reasoning behind this change.

please understand that the fact of establishing of a baseband (radio) connection has near zero security risk for host. in fact, baseband part is handled completely on bluetooth device itself. all host gets back is a notification message that remove device is trying to establish baseband connection.

number of baseband connections each bluetooth device can have is very limited, i.e. slave device can have only one baseband connection to its master device. master device can have up to 8 baseband connections to its slave devices.

default setup on pretty much all OSes is to have device accept "page scans" (i.e. be "connectable") and ignore "inquiry scans" (i.e. be NOT discoverable)

etc/defaults/bluetooth.device.conf
58 ↗(On Diff #34553)

This change will break things for existing dangerous defaults; that's endemic to fixing the danger.

Disabling the baseband connection disables L2CAP and higher portions of the bluetooth stack, which is where most vulnerabilities are discovered. No?

"Blueborne" vulnerabilities in Linux Bluez were in L2CAP, BNEP, SDP, LEAP, etc. And that's just this year, and in a bluetooth implementation that gets more eyeballs and auditing time than ours.

Earlier attacks in OBEX, etc. Blujacking, Bluesnarfing, BlueBug (RFCOMM, AT).

I just don't see any justification for enabling bluetooth by an operating system like FreeBSD. How many FreeBSD users actually use bluetooth devices? Yes, it would be convenient if we onlined and ran DHCP on all network interfaces by default, but that is not what we do. Users need to explicitly configure network/radio devices online.

etc/defaults/bluetooth.device.conf
58 ↗(On Diff #34553)

i *strongly* disagree. the only potentially "dangerous" setting is having "discoverable" on by default.

while, technically, your argument about turning off radio, is correct, i submit to you that instead of disabling radio why not just power off (or not even connect) device, or, in fact, even attempt to load kernel modules. this is just too big of a hammer.

no l2cap connections will be established unless there is a service that has l2cap socket in listen state. to my knowledge, *none* of the bluetooth services in enabled by default, so, in network terms, it would be like having an open port. not ideal, but nothing extremely dangerous.

on later point, i.e. completely disable bluetooth, i would simply commented out corresponding devd.conf section, i.e. simply do not call into /etc/rc.d/bluetooth when device arrives. this way users will have to run mergemaster and will have to resolve it one way or another.

so, to summarize, i propose

  1. keep discoverable as NO
  2. keep connectable as YES
  3. comment out ubt related section in devd.conf

i think this should address all your concerns while preserving reasonable backward compatibility

etc/defaults/bluetooth.device.conf
58 ↗(On Diff #34553)

Your proposal sounds fine to me. I'll go ahead and make that change. Thanks!

Unfortunately, it isn't clear to me how we can actually prevent devd from loading ng_ubt. devd/usb.conf is autogenerated from the USB devids supported by modules.

It is pointless to skip invoking /etc/rc.d/bluetooth, as the radio is already online once ng_ubt.ko loads.

Maybe bus_autoconf would have to grow a blacklist functionality? @hselasky, do you have any suggestion?

I would love it if loading ng_ubt.ko did not turn the radio on, and instead /etc/rc.d/bluetooth start did that. Is that a possibility, @emax ? If so, we could just remove the quietstart in devd.conf, as suggested. Unfortunately, I don't understand how the driver brings the device online.

In D12831#267334, @cem wrote:

Unfortunately, it isn't clear to me how we can actually prevent devd from loading ng_ubt. devd/usb.conf is autogenerated from the USB devids supported by modules.

that's fine. ng_ubt is simply a *HCI transport* driver. all it does is setup device for future communication.

It is pointless to skip invoking /etc/rc.d/bluetooth, as the radio is already online once ng_ubt.ko loads.

no, it is not. if you load ng_ubt you will get a device Netgraph node with defined interface that can be used to send and receive data to and from the device. that's all. if the device Netgraph node is not connected to the rest of Bluetooth Netgraph nodes, i.e. ng_hci, ng_l2cap, ng_btsocket it will simply be acting as /dev/null for anything the device may send. /etc/rc.d/bluetooth is what does the plumbing and connecting all the Bluetooth nodes together.

depending on the device, the radio may be on the moment you apply power and internal firmware is booted.

Maybe bus_autoconf would have to grow a blacklist functionality? @hselasky, do you have any suggestion?

I would love it if loading ng_ubt.ko did not turn the radio on, and instead /etc/rc.d/bluetooth start did that. Is that a possibility, @emax ? If so, we could just remove the quietstart in devd.conf, as suggested. Unfortunately, I don't understand how the driver brings the device online.

again, loading ng_ubt in *not* a problem. calling into /etc/rc.d/bluetooth is what makes things tick. no call to /etc/rc.d/bluetooth, no plumbing for device Netgraph node, and thus no data will ever escape past ng_ubt. from ng_ubt man page

DESCRIPTION

The ubt node type is both a persistent Netgraph node type and a driver
for Bluetooth USB devices.  It implements a Bluetooth USB transport layer
as per chapter H2 of the Bluetooth Specification Book v1.1.  A new node
is created when a supported USB device is plugged in.

The node has a single hook called hook.  Incoming bytes received on the
device are re-assembled into HCI frames (according to the length).  Full
HCI frames are sent out on the hook.  The node will add a HCI frame
indicator if the device did not send it.  HCI frames received on hook are
transmitted out.  The node will drop the HCI frame indicator unless the
device requires it to be present.

depending on the device, the radio may be on the moment you apply power and internal firmware is booted.

I see. Further experimentation has confirmed this. The device seems to persist the "local name" configured by /etc/rc.d/bluetooth in some NVRAM because it survives reboots. That's unfortunate.

Ok, now that we're just discussing disabling the netgraph plumbing again — why do it by hacking up devd.conf instead of adding bluetooth_enable (rcvar or not)?

Secondly, it seems that disabling the netgraph plumbing will actually hinder our goal, since it will prevent rc.d/bluetooth from configuring the device non-discoverable. Granted, the device won't be hooked up to anything in FreeBSD, but it will still respond to inquiries.

depending on the device, the radio may be on the moment you apply power and internal firmware is booted.

I see. Further experimentation has confirmed this. The device seems to persist the "local name" configured by /etc/rc.d/bluetooth in some NVRAM because it survives reboots. That's unfortunate.

like i said, please think of bluetooth device as glorified cellular modem. to greatly simplify things, its essentially "on" when power is applied.

Ok, now that we're just discussing disabling the netgraph plumbing again — why do it by hacking up devd.conf instead of adding bluetooth_enable (rcvar or not)?

i've already explained my reasoning behind not using rcvar. to repeat myself, rcvar is "special", and, since /etc/rc.d/bluetooth is not expected to run during normal startup/shutdown sequence, in my opinion, rcvar should remain empty.

from user's point of view, having Netgraph plumbing setup is beneficial. without it commands like hccontrol(8) etc. will not work. having /etc/rc.d/bluetooth ran and do nothing (not even produce a warning/error) is, imo, POLA violation.

Secondly, it seems that disabling the netgraph plumbing will actually hinder our goal, since it will prevent rc.d/bluetooth from configuring the device non-discoverable. Granted, the device won't be hooked up to anything in FreeBSD, but it will still respond to inquiries.

right. that is why i suggested to simply set "discoverable" to "NO" by default, and, do not run any bluetooth services. ultra secure / custom setups can always use WITHOUT_BLUETOOTH=YES knob and avoid dealing with it. GENERIC / default setup will not respond to inquiry while still providing ability to run hccontrol(8) and friends. everything in bluetooth is tied to device's BD_ADDR. inquiry is the only "official" way (i know of) to obtain remote device's BD_ADDR. no inquiry answer == no remote BD_ADDR, and, no remove BD_ADDR == no baseband connection. bluetooth is point-to-point by design and there is no "promiscuous/monitor" mode on bluetooth devices. you can not just sniff packets using off-the-shelf device.

In D12831#267600, @emax wrote:

Ok, now that we're just discussing disabling the netgraph plumbing again — why do it by hacking up devd.conf instead of adding bluetooth_enable (rcvar or not)?

from user's point of view, having Netgraph plumbing setup is beneficial. without it commands like hccontrol(8) etc. will not work. having /etc/rc.d/bluetooth ran and do nothing (not even produce a warning/error) is, imo, POLA violation.

The proposal would add an error message: Cannot 'start' bluetooth. Set bluetooth_enable to YES in /etc/rc.conf or use 'onestart' instead of 'start'. (using rcvar's automatic plumbing) or with an explicit err not using rcvar:

if ! checkyesno bluetooth_enable; then
        err 1 "Cannot '$1' bluetooth. Set blah to YES."
fi

(Although this approach breaks overrides like onestart or forcestart.)

Secondly, it seems that disabling the netgraph plumbing will actually hinder our goal, since it will prevent rc.d/bluetooth from configuring the device non-discoverable. Granted, the device won't be hooked up to anything in FreeBSD, but it will still respond to inquiries.

right. that is why i suggested to simply set "discoverable" to "NO" by default, and, do not run any bluetooth services. ultra secure / custom setups can always use WITHOUT_BLUETOOTH=YES knob and avoid dealing with it. GENERIC / default setup will not respond to inquiry while still providing ability to run hccontrol(8) and friends.

Right. Let's set discoverable to NO as a first step everybody agrees on.

everything in bluetooth is tied to device's BD_ADDR. inquiry is the only "official" way (i know of) to obtain remote device's BD_ADDR.

It isn't the only way. One can scan all of BD_ADDR space (24 bits random + 24 bits manufacturer prefix that is neither random nor fully populated) using page/connection requests. https://www.sans.edu/cyber-research/security-laboratory/article/bluetooth :

While keeping Bluetooth devices in non-discoverable mode is a recommended security practice, it does not prevent an attacker from being able to capture information about an active piconet in progress. While the Bluetooth frame header does not transmit the full BD_ADDR information (unlike IEEE 802.11 and Ethern dete cap information three bytes of BD_ADDR are known, an attacker can send con request messages to every common BD_ADDR prefix or OUI until the full BD_ADDR is known. A list of common BD_ADDR prefixes are available through the results of the BNAP, BNAP project at [7]. Using this list, an attacker can test all known Bluetooth OUI values in less than 2 minutes. Once a response is received for a probe, the attacker knows the full BD_ADDR of the target device.

cem edited the summary of this revision. (Show Details)

Merely turn off discoverable by default for now. It seems to be the common
ground.

cem retitled this revision from bluetooth: Default to not discoverable nor connectable to bluetooth: Default to discoverable off.Nov 1 2017, 5:03 PM
cem edited the summary of this revision. (Show Details)
This revision is now accepted and ready to land.Nov 1 2017, 5:30 PM
This revision was automatically updated to reflect the committed changes.