diff mbox series

[v2,2/6] driver core: Add common support to skip probe for un-authorized devices

Message ID 20210930010511.3387967-3-sathyanarayanan.kuppuswamy@linux.intel.com (mailing list archive)
State Not Applicable
Delegated to: Bjorn Helgaas
Headers show
Series Add device filter support | expand

Commit Message

Kuppuswamy Sathyanarayanan Sept. 30, 2021, 1:05 a.m. UTC
While the common case for device-authorization is to skip probe of
unauthorized devices, some buses may still want to emit a message on
probe failure (Thunderbolt), or base probe failures on the
authorization status of a related device like a parent (USB). So add
an option (has_probe_authorization) in struct bus_type for the bus
driver to own probe authorization policy.

Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 drivers/base/dd.c            | 5 +++++
 drivers/thunderbolt/domain.c | 1 +
 drivers/usb/core/driver.c    | 1 +
 include/linux/device/bus.h   | 4 ++++
 4 files changed, 11 insertions(+)

Comments

Michael S. Tsirkin Sept. 30, 2021, 10:59 a.m. UTC | #1
On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> While the common case for device-authorization is to skip probe of
> unauthorized devices, some buses may still want to emit a message on
> probe failure (Thunderbolt), or base probe failures on the
> authorization status of a related device like a parent (USB). So add
> an option (has_probe_authorization) in struct bus_type for the bus
> driver to own probe authorization policy.
> 
> Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>



So what e.g. the PCI patch
https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
actually proposes is a list of
allowed drivers, not devices. Doing it at the device level
has disadvantages, for example some devices might have a legacy
unsafe driver, or an out of tree driver. It also does not
address drivers that poke at hardware during init.

Accordingly, I think the right thing to do is to skip
driver init for disallowed drivers, not skip probe
for specific devices.


> ---
>  drivers/base/dd.c            | 5 +++++
>  drivers/thunderbolt/domain.c | 1 +
>  drivers/usb/core/driver.c    | 1 +
>  include/linux/device/bus.h   | 4 ++++
>  4 files changed, 11 insertions(+)
> 
> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> index 68ea1f949daa..0cd03ac7d3b1 100644
> --- a/drivers/base/dd.c
> +++ b/drivers/base/dd.c
> @@ -544,6 +544,11 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>  			   !drv->suppress_bind_attrs;
>  	int ret;
>  
> +	if (!dev->authorized && !dev->bus->has_probe_authorization) {
> +		dev_dbg(dev, "Device is not authorized\n");
> +		return -ENODEV;
> +	}
> +
>  	if (defer_all_probes) {
>  		/*
>  		 * Value of defer_all_probes can be set only by
> diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
> index 3e39686eff14..6de8a366b796 100644
> --- a/drivers/thunderbolt/domain.c
> +++ b/drivers/thunderbolt/domain.c
> @@ -321,6 +321,7 @@ struct bus_type tb_bus_type = {
>  	.probe = tb_service_probe,
>  	.remove = tb_service_remove,
>  	.shutdown = tb_service_shutdown,
> +	.has_probe_authorization = true,
>  };
>  
>  static void tb_domain_release(struct device *dev)
> diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
> index fb476665f52d..f57b5a7a90ca 100644
> --- a/drivers/usb/core/driver.c
> +++ b/drivers/usb/core/driver.c
> @@ -2028,4 +2028,5 @@ struct bus_type usb_bus_type = {
>  	.match =	usb_device_match,
>  	.uevent =	usb_uevent,
>  	.need_parent_lock =	true,
> +	.has_probe_authorization = true,
>  };
> diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h
> index 062777a45a74..571a2f6e7c1d 100644
> --- a/include/linux/device/bus.h
> +++ b/include/linux/device/bus.h
> @@ -69,6 +69,9 @@ struct fwnode_handle;
>   * @lock_key:	Lock class key for use by the lock validator
>   * @need_parent_lock:	When probing or removing a device on this bus, the
>   *			device core should lock the device's parent.
> + * @has_probe_authorization: Set true to indicate to the driver-core to skip
> + *			     the authorization checks and let bus drivers
> + *			     handle it locally.
>   *
>   * A bus is a channel between the processor and one or more devices. For the
>   * purposes of the device model, all devices are connected via a bus, even if
> @@ -112,6 +115,7 @@ struct bus_type {
>  	struct lock_class_key lock_key;
>  
>  	bool need_parent_lock;
> +	bool has_probe_authorization;
>  };
>  
>  extern int __must_check bus_register(struct bus_type *bus);
> -- 
> 2.25.1
Greg Kroah-Hartman Sept. 30, 2021, 1:52 p.m. UTC | #2
On Thu, Sep 30, 2021 at 06:59:36AM -0400, Michael S. Tsirkin wrote:
> On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > While the common case for device-authorization is to skip probe of
> > unauthorized devices, some buses may still want to emit a message on
> > probe failure (Thunderbolt), or base probe failures on the
> > authorization status of a related device like a parent (USB). So add
> > an option (has_probe_authorization) in struct bus_type for the bus
> > driver to own probe authorization policy.
> > 
> > Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> > Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> 
> 
> 
> So what e.g. the PCI patch
> https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
> actually proposes is a list of
> allowed drivers, not devices. Doing it at the device level
> has disadvantages, for example some devices might have a legacy
> unsafe driver, or an out of tree driver. It also does not
> address drivers that poke at hardware during init.

Doing it at a device level is the only sane way to do this.

A user needs to say "this device is allowed to be controlled by this
driver".  This is the trust model that USB has had for over a decade and
what thunderbolt also has.

> Accordingly, I think the right thing to do is to skip
> driver init for disallowed drivers, not skip probe
> for specific devices.

What do you mean by "driver init"?  module_init()?

No driver should be touching hardware in their module init call.  They
should only be touching it in the probe callback as that is the only
time they are ever allowed to talk to hardware.  Specifically the device
that has been handed to them.

If there are in-kernel PCI drivers that do not do this, they need to be
fixed today.

We don't care about out-of-tree drivers for obvious reasons that we have
no control over them.

thanks,

greg k-h
Michael S. Tsirkin Sept. 30, 2021, 2:38 p.m. UTC | #3
On Thu, Sep 30, 2021 at 03:52:52PM +0200, Greg Kroah-Hartman wrote:
> On Thu, Sep 30, 2021 at 06:59:36AM -0400, Michael S. Tsirkin wrote:
> > On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > > While the common case for device-authorization is to skip probe of
> > > unauthorized devices, some buses may still want to emit a message on
> > > probe failure (Thunderbolt), or base probe failures on the
> > > authorization status of a related device like a parent (USB). So add
> > > an option (has_probe_authorization) in struct bus_type for the bus
> > > driver to own probe authorization policy.
> > > 
> > > Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> > > Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> > 
> > 
> > 
> > So what e.g. the PCI patch
> > https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
> > actually proposes is a list of
> > allowed drivers, not devices. Doing it at the device level
> > has disadvantages, for example some devices might have a legacy
> > unsafe driver, or an out of tree driver. It also does not
> > address drivers that poke at hardware during init.
> 
> Doing it at a device level is the only sane way to do this.
> 
> A user needs to say "this device is allowed to be controlled by this
> driver".  This is the trust model that USB has had for over a decade and
> what thunderbolt also has.
> 
> > Accordingly, I think the right thing to do is to skip
> > driver init for disallowed drivers, not skip probe
> > for specific devices.
> 
> What do you mean by "driver init"?  module_init()?
> 
> No driver should be touching hardware in their module init call.  They
> should only be touching it in the probe callback as that is the only
> time they are ever allowed to talk to hardware.  Specifically the device
> that has been handed to them.
> 
> If there are in-kernel PCI drivers that do not do this, they need to be
> fixed today.
> 
> We don't care about out-of-tree drivers for obvious reasons that we have
> no control over them.
> 
> thanks,
> 
> greg k-h

Well talk to Andi about it pls :)
https://lore.kernel.org/r/ad1e41d1-3f4e-8982-16ea-18a3b2c04019%40linux.intel.com
Alan Stern Sept. 30, 2021, 2:43 p.m. UTC | #4
On Thu, Sep 30, 2021 at 03:52:52PM +0200, Greg Kroah-Hartman wrote:
> On Thu, Sep 30, 2021 at 06:59:36AM -0400, Michael S. Tsirkin wrote:
> > On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > > While the common case for device-authorization is to skip probe of
> > > unauthorized devices, some buses may still want to emit a message on
> > > probe failure (Thunderbolt), or base probe failures on the
> > > authorization status of a related device like a parent (USB). So add
> > > an option (has_probe_authorization) in struct bus_type for the bus
> > > driver to own probe authorization policy.
> > > 
> > > Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> > > Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> > 
> > 
> > 
> > So what e.g. the PCI patch
> > https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
> > actually proposes is a list of
> > allowed drivers, not devices. Doing it at the device level
> > has disadvantages, for example some devices might have a legacy
> > unsafe driver, or an out of tree driver. It also does not
> > address drivers that poke at hardware during init.
> 
> Doing it at a device level is the only sane way to do this.
> 
> A user needs to say "this device is allowed to be controlled by this
> driver".  This is the trust model that USB has had for over a decade and
> what thunderbolt also has.
> 
> > Accordingly, I think the right thing to do is to skip
> > driver init for disallowed drivers, not skip probe
> > for specific devices.
> 
> What do you mean by "driver init"?  module_init()?
> 
> No driver should be touching hardware in their module init call.  They
> should only be touching it in the probe callback as that is the only
> time they are ever allowed to talk to hardware.  Specifically the device
> that has been handed to them.
> 
> If there are in-kernel PCI drivers that do not do this, they need to be
> fixed today.
> 
> We don't care about out-of-tree drivers for obvious reasons that we have
> no control over them.

I don't see any point in talking about "untrusted drivers".  If a 
driver isn't trusted then it doesn't belong in your kernel.  Period.  
When you load a driver into your kernel, you are implicitly trusting 
it (aside from limitations imposed by security modules).  The code 
it contains, the module_init code in particular, runs with full 
superuser permissions.

What use is there in loading a driver but telling the kernel "I don't 
trust this driver, so don't allow it to probe any devices"?  Why not 
just blacklist it so that it never gets modprobed in the first place?

Alan Stern
Michael S. Tsirkin Sept. 30, 2021, 2:48 p.m. UTC | #5
On Thu, Sep 30, 2021 at 10:43:05AM -0400, Alan Stern wrote:
> On Thu, Sep 30, 2021 at 03:52:52PM +0200, Greg Kroah-Hartman wrote:
> > On Thu, Sep 30, 2021 at 06:59:36AM -0400, Michael S. Tsirkin wrote:
> > > On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > > > While the common case for device-authorization is to skip probe of
> > > > unauthorized devices, some buses may still want to emit a message on
> > > > probe failure (Thunderbolt), or base probe failures on the
> > > > authorization status of a related device like a parent (USB). So add
> > > > an option (has_probe_authorization) in struct bus_type for the bus
> > > > driver to own probe authorization policy.
> > > > 
> > > > Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> > > > Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> > > 
> > > 
> > > 
> > > So what e.g. the PCI patch
> > > https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
> > > actually proposes is a list of
> > > allowed drivers, not devices. Doing it at the device level
> > > has disadvantages, for example some devices might have a legacy
> > > unsafe driver, or an out of tree driver. It also does not
> > > address drivers that poke at hardware during init.
> > 
> > Doing it at a device level is the only sane way to do this.
> > 
> > A user needs to say "this device is allowed to be controlled by this
> > driver".  This is the trust model that USB has had for over a decade and
> > what thunderbolt also has.
> > 
> > > Accordingly, I think the right thing to do is to skip
> > > driver init for disallowed drivers, not skip probe
> > > for specific devices.
> > 
> > What do you mean by "driver init"?  module_init()?
> > 
> > No driver should be touching hardware in their module init call.  They
> > should only be touching it in the probe callback as that is the only
> > time they are ever allowed to talk to hardware.  Specifically the device
> > that has been handed to them.
> > 
> > If there are in-kernel PCI drivers that do not do this, they need to be
> > fixed today.
> > 
> > We don't care about out-of-tree drivers for obvious reasons that we have
> > no control over them.
> 
> I don't see any point in talking about "untrusted drivers".  If a 
> driver isn't trusted then it doesn't belong in your kernel.  Period.  
> When you load a driver into your kernel, you are implicitly trusting 
> it (aside from limitations imposed by security modules).  The code 
> it contains, the module_init code in particular, runs with full 
> superuser permissions.
> 
> What use is there in loading a driver but telling the kernel "I don't 
> trust this driver, so don't allow it to probe any devices"?  Why not 
> just blacklist it so that it never gets modprobed in the first place?
> 
> Alan Stern

When the driver is built-in, it seems useful to be able to block it
without rebuilding the kernel. This is just flipping it around
and using an allow-list for cases where you want to severly
limit the available functionality.
Greg Kroah-Hartman Sept. 30, 2021, 2:49 p.m. UTC | #6
On Thu, Sep 30, 2021 at 10:38:42AM -0400, Michael S. Tsirkin wrote:
> On Thu, Sep 30, 2021 at 03:52:52PM +0200, Greg Kroah-Hartman wrote:
> > On Thu, Sep 30, 2021 at 06:59:36AM -0400, Michael S. Tsirkin wrote:
> > > On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > > > While the common case for device-authorization is to skip probe of
> > > > unauthorized devices, some buses may still want to emit a message on
> > > > probe failure (Thunderbolt), or base probe failures on the
> > > > authorization status of a related device like a parent (USB). So add
> > > > an option (has_probe_authorization) in struct bus_type for the bus
> > > > driver to own probe authorization policy.
> > > > 
> > > > Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> > > > Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> > > 
> > > 
> > > 
> > > So what e.g. the PCI patch
> > > https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
> > > actually proposes is a list of
> > > allowed drivers, not devices. Doing it at the device level
> > > has disadvantages, for example some devices might have a legacy
> > > unsafe driver, or an out of tree driver. It also does not
> > > address drivers that poke at hardware during init.
> > 
> > Doing it at a device level is the only sane way to do this.
> > 
> > A user needs to say "this device is allowed to be controlled by this
> > driver".  This is the trust model that USB has had for over a decade and
> > what thunderbolt also has.
> > 
> > > Accordingly, I think the right thing to do is to skip
> > > driver init for disallowed drivers, not skip probe
> > > for specific devices.
> > 
> > What do you mean by "driver init"?  module_init()?
> > 
> > No driver should be touching hardware in their module init call.  They
> > should only be touching it in the probe callback as that is the only
> > time they are ever allowed to talk to hardware.  Specifically the device
> > that has been handed to them.
> > 
> > If there are in-kernel PCI drivers that do not do this, they need to be
> > fixed today.
> > 
> > We don't care about out-of-tree drivers for obvious reasons that we have
> > no control over them.
> > 
> > thanks,
> > 
> > greg k-h
> 
> Well talk to Andi about it pls :)
> https://lore.kernel.org/r/ad1e41d1-3f4e-8982-16ea-18a3b2c04019%40linux.intel.com

As Alan said, the minute you allow any driver to get into your kernel,
it can do anything it wants to.

So just don't allow drivers to be added to your kernel if you care about
these things.  The system owner has that mechanism today.

thanks,

greg k-h
Michael S. Tsirkin Sept. 30, 2021, 2:58 p.m. UTC | #7
On Thu, Sep 30, 2021 at 10:43:05AM -0400, Alan Stern wrote:
> I don't see any point in talking about "untrusted drivers".  If a 
> driver isn't trusted then it doesn't belong in your kernel.  Period.  
> When you load a driver into your kernel, you are implicitly trusting 
> it (aside from limitations imposed by security modules).

Trusting it to do what? Historically a ton of drivers did not
validate input from devices they drive. Most still don't.

> The code 
> it contains, the module_init code in particular, runs with full 
> superuser permissions.
Michael S. Tsirkin Sept. 30, 2021, 3 p.m. UTC | #8
On Thu, Sep 30, 2021 at 04:49:23PM +0200, Greg Kroah-Hartman wrote:
> On Thu, Sep 30, 2021 at 10:38:42AM -0400, Michael S. Tsirkin wrote:
> > On Thu, Sep 30, 2021 at 03:52:52PM +0200, Greg Kroah-Hartman wrote:
> > > On Thu, Sep 30, 2021 at 06:59:36AM -0400, Michael S. Tsirkin wrote:
> > > > On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > > > > While the common case for device-authorization is to skip probe of
> > > > > unauthorized devices, some buses may still want to emit a message on
> > > > > probe failure (Thunderbolt), or base probe failures on the
> > > > > authorization status of a related device like a parent (USB). So add
> > > > > an option (has_probe_authorization) in struct bus_type for the bus
> > > > > driver to own probe authorization policy.
> > > > > 
> > > > > Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> > > > > Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> > > > 
> > > > 
> > > > 
> > > > So what e.g. the PCI patch
> > > > https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
> > > > actually proposes is a list of
> > > > allowed drivers, not devices. Doing it at the device level
> > > > has disadvantages, for example some devices might have a legacy
> > > > unsafe driver, or an out of tree driver. It also does not
> > > > address drivers that poke at hardware during init.
> > > 
> > > Doing it at a device level is the only sane way to do this.
> > > 
> > > A user needs to say "this device is allowed to be controlled by this
> > > driver".  This is the trust model that USB has had for over a decade and
> > > what thunderbolt also has.
> > > 
> > > > Accordingly, I think the right thing to do is to skip
> > > > driver init for disallowed drivers, not skip probe
> > > > for specific devices.
> > > 
> > > What do you mean by "driver init"?  module_init()?
> > > 
> > > No driver should be touching hardware in their module init call.  They
> > > should only be touching it in the probe callback as that is the only
> > > time they are ever allowed to talk to hardware.  Specifically the device
> > > that has been handed to them.
> > > 
> > > If there are in-kernel PCI drivers that do not do this, they need to be
> > > fixed today.
> > > 
> > > We don't care about out-of-tree drivers for obvious reasons that we have
> > > no control over them.
> > > 
> > > thanks,
> > > 
> > > greg k-h
> > 
> > Well talk to Andi about it pls :)
> > https://lore.kernel.org/r/ad1e41d1-3f4e-8982-16ea-18a3b2c04019%40linux.intel.com
> 
> As Alan said, the minute you allow any driver to get into your kernel,
> it can do anything it wants to.
> 
> So just don't allow drivers to be added to your kernel if you care about
> these things.  The system owner has that mechanism today.
> 
> thanks,
> 
> greg k-h

The "it" that I referred to is the claim that no driver should be
touching hardware in their module init call. Andi seems to think
such drivers are worth working around with a special remap API.
Greg Kroah-Hartman Sept. 30, 2021, 3:22 p.m. UTC | #9
On Thu, Sep 30, 2021 at 11:00:07AM -0400, Michael S. Tsirkin wrote:
> On Thu, Sep 30, 2021 at 04:49:23PM +0200, Greg Kroah-Hartman wrote:
> > On Thu, Sep 30, 2021 at 10:38:42AM -0400, Michael S. Tsirkin wrote:
> > > On Thu, Sep 30, 2021 at 03:52:52PM +0200, Greg Kroah-Hartman wrote:
> > > > On Thu, Sep 30, 2021 at 06:59:36AM -0400, Michael S. Tsirkin wrote:
> > > > > On Wed, Sep 29, 2021 at 06:05:07PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > > > > > While the common case for device-authorization is to skip probe of
> > > > > > unauthorized devices, some buses may still want to emit a message on
> > > > > > probe failure (Thunderbolt), or base probe failures on the
> > > > > > authorization status of a related device like a parent (USB). So add
> > > > > > an option (has_probe_authorization) in struct bus_type for the bus
> > > > > > driver to own probe authorization policy.
> > > > > > 
> > > > > > Reviewed-by: Dan Williams <dan.j.williams@intel.com>
> > > > > > Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> > > > > 
> > > > > 
> > > > > 
> > > > > So what e.g. the PCI patch
> > > > > https://lore.kernel.org/all/CACK8Z6E8pjVeC934oFgr=VB3pULx_GyT2NkzAogdRQJ9TKSX9A@mail.gmail.com/
> > > > > actually proposes is a list of
> > > > > allowed drivers, not devices. Doing it at the device level
> > > > > has disadvantages, for example some devices might have a legacy
> > > > > unsafe driver, or an out of tree driver. It also does not
> > > > > address drivers that poke at hardware during init.
> > > > 
> > > > Doing it at a device level is the only sane way to do this.
> > > > 
> > > > A user needs to say "this device is allowed to be controlled by this
> > > > driver".  This is the trust model that USB has had for over a decade and
> > > > what thunderbolt also has.
> > > > 
> > > > > Accordingly, I think the right thing to do is to skip
> > > > > driver init for disallowed drivers, not skip probe
> > > > > for specific devices.
> > > > 
> > > > What do you mean by "driver init"?  module_init()?
> > > > 
> > > > No driver should be touching hardware in their module init call.  They
> > > > should only be touching it in the probe callback as that is the only
> > > > time they are ever allowed to talk to hardware.  Specifically the device
> > > > that has been handed to them.
> > > > 
> > > > If there are in-kernel PCI drivers that do not do this, they need to be
> > > > fixed today.
> > > > 
> > > > We don't care about out-of-tree drivers for obvious reasons that we have
> > > > no control over them.
> > > > 
> > > > thanks,
> > > > 
> > > > greg k-h
> > > 
> > > Well talk to Andi about it pls :)
> > > https://lore.kernel.org/r/ad1e41d1-3f4e-8982-16ea-18a3b2c04019%40linux.intel.com
> > 
> > As Alan said, the minute you allow any driver to get into your kernel,
> > it can do anything it wants to.
> > 
> > So just don't allow drivers to be added to your kernel if you care about
> > these things.  The system owner has that mechanism today.
> > 
> > thanks,
> > 
> > greg k-h
> 
> The "it" that I referred to is the claim that no driver should be
> touching hardware in their module init call. Andi seems to think
> such drivers are worth working around with a special remap API.

Andi is wrong.
Alan Stern Sept. 30, 2021, 3:32 p.m. UTC | #10
On Thu, Sep 30, 2021 at 10:48:54AM -0400, Michael S. Tsirkin wrote:
> On Thu, Sep 30, 2021 at 10:43:05AM -0400, Alan Stern wrote:
> > I don't see any point in talking about "untrusted drivers".  If a 
> > driver isn't trusted then it doesn't belong in your kernel.  Period.  
> > When you load a driver into your kernel, you are implicitly trusting 
> > it (aside from limitations imposed by security modules).  The code 
> > it contains, the module_init code in particular, runs with full 
> > superuser permissions.
> > 
> > What use is there in loading a driver but telling the kernel "I don't 
> > trust this driver, so don't allow it to probe any devices"?  Why not 
> > just blacklist it so that it never gets modprobed in the first place?
> > 
> > Alan Stern
> 
> When the driver is built-in, it seems useful to be able to block it
> without rebuilding the kernel. This is just flipping it around
> and using an allow-list for cases where you want to severly
> limit the available functionality.

Does this make sense?

The only way to tell the kernel to block a built-in driver is by 
using some boot-command-line option.  Otherwise the driver's init 
code will run before you have a chance to tell the kernel anything at 
all.

So if you change your mind about whether a driver should be blocked, 
all you have to do is remove the blocking option from the command 
line and reboot.  No kernel rebuild is necessary.

Alan Stern
Alan Stern Sept. 30, 2021, 3:35 p.m. UTC | #11
On Thu, Sep 30, 2021 at 10:58:07AM -0400, Michael S. Tsirkin wrote:
> On Thu, Sep 30, 2021 at 10:43:05AM -0400, Alan Stern wrote:
> > I don't see any point in talking about "untrusted drivers".  If a 
> > driver isn't trusted then it doesn't belong in your kernel.  Period.  
> > When you load a driver into your kernel, you are implicitly trusting 
> > it (aside from limitations imposed by security modules).
> 
> Trusting it to do what? Historically a ton of drivers did not
> validate input from devices they drive. Most still don't.

Trusting it to behave properly (i.e., not destroy your system, among 
other things).

The fact that many drivers haven't been trustworthy is beside the 
point.  By loading them into your kernel, you are trusting them 
regardless.  In the end, you may regret having done so.  :-(

Alan Stern
Michael S. Tsirkin Sept. 30, 2021, 3:52 p.m. UTC | #12
On Thu, Sep 30, 2021 at 11:32:41AM -0400, Alan Stern wrote:
> On Thu, Sep 30, 2021 at 10:48:54AM -0400, Michael S. Tsirkin wrote:
> > On Thu, Sep 30, 2021 at 10:43:05AM -0400, Alan Stern wrote:
> > > I don't see any point in talking about "untrusted drivers".  If a 
> > > driver isn't trusted then it doesn't belong in your kernel.  Period.  
> > > When you load a driver into your kernel, you are implicitly trusting 
> > > it (aside from limitations imposed by security modules).  The code 
> > > it contains, the module_init code in particular, runs with full 
> > > superuser permissions.
> > > 
> > > What use is there in loading a driver but telling the kernel "I don't 
> > > trust this driver, so don't allow it to probe any devices"?  Why not 
> > > just blacklist it so that it never gets modprobed in the first place?
> > > 
> > > Alan Stern
> > 
> > When the driver is built-in, it seems useful to be able to block it
> > without rebuilding the kernel. This is just flipping it around
> > and using an allow-list for cases where you want to severly
> > limit the available functionality.
> 
> Does this make sense?
> 
> The only way to tell the kernel to block a built-in driver is by 
> using some boot-command-line option.  Otherwise the driver's init 
> code will run before you have a chance to tell the kernel anything at 
> all.
> 
> So if you change your mind about whether a driver should be blocked, 
> all you have to do is remove the blocking option from the command 
> line and reboot.  No kernel rebuild is necessary.
> 
> Alan Stern

Right.
Michael S. Tsirkin Sept. 30, 2021, 3:59 p.m. UTC | #13
On Thu, Sep 30, 2021 at 11:35:09AM -0400, Alan Stern wrote:
> On Thu, Sep 30, 2021 at 10:58:07AM -0400, Michael S. Tsirkin wrote:
> > On Thu, Sep 30, 2021 at 10:43:05AM -0400, Alan Stern wrote:
> > > I don't see any point in talking about "untrusted drivers".  If a 
> > > driver isn't trusted then it doesn't belong in your kernel.  Period.  
> > > When you load a driver into your kernel, you are implicitly trusting 
> > > it (aside from limitations imposed by security modules).
> > 
> > Trusting it to do what? Historically a ton of drivers did not
> > validate input from devices they drive. Most still don't.
> 
> Trusting it to behave properly (i.e., not destroy your system, among 
> other things).

I don't think the current mitigations under discussion here are about
keeping the system working. In fact most encrypted VM configs tend to
stop booting as a preferred way to handle security issues.

> The fact that many drivers haven't been trustworthy is beside the 
> point.  By loading them into your kernel, you are trusting them 
> regardless.  In the end, you may regret having done so.  :-(
> 
> Alan Stern
Andi Kleen Sept. 30, 2021, 5:17 p.m. UTC | #14
>> The "it" that I referred to is the claim that no driver should be
>> touching hardware in their module init call. Andi seems to think
>> such drivers are worth working around with a special remap API.
> Andi is wrong.

While overall it's a small percentage of the total, there are still 
quite a few drivers that do touch hardware in init functions. Sometimes 
for good reasons -- they need to do some extra probing to discover 
something that is not enumerated -- sometimes just because it's very old 
legacy code that predates the modern driver model.

The legacy drivers could be fixed, but nobody really wants to touch them 
anymore and they're impossible to test.

The drivers that probe something that is not enumerated in a standard 
way have no choice, it cannot be implemented in a different way.

So instead we're using a "firewall" the prevents these drivers from 
doing bad things by not allowing ioremap access unless opted in, and 
also do some filtering on the IO ports The device filter is still the 
primary mechanism, the ioremap filtering is just belts and suspenders 
for those odd cases.

If you want we can send an exact list, we did some analysis using a 
patched smatch tool.

-Andi
Greg Kroah-Hartman Sept. 30, 2021, 5:23 p.m. UTC | #15
On Thu, Sep 30, 2021 at 10:17:09AM -0700, Andi Kleen wrote:
> 
> > > The "it" that I referred to is the claim that no driver should be
> > > touching hardware in their module init call. Andi seems to think
> > > such drivers are worth working around with a special remap API.
> > Andi is wrong.
> 
> While overall it's a small percentage of the total, there are still quite a
> few drivers that do touch hardware in init functions. Sometimes for good
> reasons -- they need to do some extra probing to discover something that is
> not enumerated -- sometimes just because it's very old legacy code that
> predates the modern driver model.

Are any of them in the kernel today?

PCI drivers should not be messing with this, we have had well over a
decade to fix that up.

> The legacy drivers could be fixed, but nobody really wants to touch them
> anymore and they're impossible to test.

Pointers to them?

> The drivers that probe something that is not enumerated in a standard way
> have no choice, it cannot be implemented in a different way.

PCI devices are not enumerated in a standard way???

> So instead we're using a "firewall" the prevents these drivers from doing
> bad things by not allowing ioremap access unless opted in, and also do some
> filtering on the IO ports The device filter is still the primary mechanism,
> the ioremap filtering is just belts and suspenders for those odd cases.

That's horrible, don't try to protect the kernel from itself.  Just fix
the drivers.

If you point me at them, I will be glad to have a look and throw some
interns on them.

But really, you all could have fixed them up by now if Intel really
cared about it :(

> If you want we can send an exact list, we did some analysis using a patched
> smatch tool.

Please do.

thanks,

greg k-h
Andi Kleen Sept. 30, 2021, 7:15 p.m. UTC | #16
On 9/30/2021 10:23 AM, Greg Kroah-Hartman wrote:
> On Thu, Sep 30, 2021 at 10:17:09AM -0700, Andi Kleen wrote:
>>>> The "it" that I referred to is the claim that no driver should be
>>>> touching hardware in their module init call. Andi seems to think
>>>> such drivers are worth working around with a special remap API.
>>> Andi is wrong.
>> While overall it's a small percentage of the total, there are still quite a
>> few drivers that do touch hardware in init functions. Sometimes for good
>> reasons -- they need to do some extra probing to discover something that is
>> not enumerated -- sometimes just because it's very old legacy code that
>> predates the modern driver model.
> Are any of them in the kernel today?
>
> PCI drivers should not be messing with this, we have had well over a
> decade to fix that up.


It's not just PCI driver, it's every driver that can do io port / MMIO / 
MSR / config space accesses.


Maybe read the excellent article from Jon on this:

https://lwn.net/Articles/865918/


>
>> The legacy drivers could be fixed, but nobody really wants to touch them
>> anymore and they're impossible to test.
> Pointers to them?

For example if you look over old SCSI drivers in drivers/scsi/*.c there 
is a substantial number that has a module init longer than just 
registering a driver. As a single example look at drivers/scsi/BusLogic.c

There were also quite a few platform drivers like this.


>
>> The drivers that probe something that is not enumerated in a standard way
>> have no choice, it cannot be implemented in a different way.
> PCI devices are not enumerated in a standard way???

The pci devices are enumerated in a standard way, but typically the 
driver also needs something else outside PCI that needs some other 
probing mechanism.


>
>> So instead we're using a "firewall" the prevents these drivers from doing
>> bad things by not allowing ioremap access unless opted in, and also do some
>> filtering on the IO ports The device filter is still the primary mechanism,
>> the ioremap filtering is just belts and suspenders for those odd cases.
> That's horrible, don't try to protect the kernel from itself.  Just fix
> the drivers.

I thought we had already established this last time we discussed it.

That's completely impractical. We cannot harden thousands of drivers, 
especially since it would be all wasted work since nobody will ever need 
them in virtual guests. Even if we could harden them how would such a 
work be maintained long term? Using a firewall and filtering mechanism 
is much saner for everyone.

-Andi
Andi Kleen Sept. 30, 2021, 7:23 p.m. UTC | #17
> I don't think the current mitigations under discussion here are about
> keeping the system working. In fact most encrypted VM configs tend to
> stop booting as a preferred way to handle security issues.

Maybe we should avoid the "trusted" term here. We're only really using 
it because USB is using it and we're now using a common framework like 
Greg requested. But I don't think it's the right way to think about it.

We usually call the drivers "hardened". The requirement for a hardened 
driver is that all interactions through MMIO/port/config space IO/MSRs 
are sanitized and do not cause memory safety issues or other information 
leaks. Other than that there is no requirement on the functionality. In 
particular DOS is ok since a malicious hypervisor can decide to not run 
the guest at any time anyways.

Someone loading an malicious driver inside the guest would be out of 
scope. If an attacker can do that inside the guest you already violated 
the security mechanisms and there are likely easier ways to take over 
the guest or leak data.

The goal of the device filter mechanism is to prevent loading unhardened 
drivers that could be exploited without them being themselves malicious.


-Andi
Alan Stern Sept. 30, 2021, 8:44 p.m. UTC | #18
On Thu, Sep 30, 2021 at 12:23:36PM -0700, Andi Kleen wrote:
> 
> > I don't think the current mitigations under discussion here are about
> > keeping the system working. In fact most encrypted VM configs tend to
> > stop booting as a preferred way to handle security issues.
> 
> Maybe we should avoid the "trusted" term here. We're only really using it
> because USB is using it and we're now using a common framework like Greg
> requested. But I don't think it's the right way to think about it.
> 
> We usually call the drivers "hardened". The requirement for a hardened
> driver is that all interactions through MMIO/port/config space IO/MSRs are
> sanitized and do not cause memory safety issues or other information leaks.
> Other than that there is no requirement on the functionality. In particular
> DOS is ok since a malicious hypervisor can decide to not run the guest at
> any time anyways.
> 
> Someone loading an malicious driver inside the guest would be out of scope.
> If an attacker can do that inside the guest you already violated the
> security mechanisms and there are likely easier ways to take over the guest
> or leak data.
> 
> The goal of the device filter mechanism is to prevent loading unhardened
> drivers that could be exploited without them being themselves malicious.

If all you want to do is prevent someone from loading a bunch of 
drivers that you have identified as unhardened, why not just use a 
modprobe blacklist?  Am I missing something?

Alan Stern
Dan Williams Sept. 30, 2021, 8:52 p.m. UTC | #19
On Thu, Sep 30, 2021 at 1:44 PM Alan Stern <stern@rowland.harvard.edu> wrote:
>
> On Thu, Sep 30, 2021 at 12:23:36PM -0700, Andi Kleen wrote:
> >
> > > I don't think the current mitigations under discussion here are about
> > > keeping the system working. In fact most encrypted VM configs tend to
> > > stop booting as a preferred way to handle security issues.
> >
> > Maybe we should avoid the "trusted" term here. We're only really using it
> > because USB is using it and we're now using a common framework like Greg
> > requested. But I don't think it's the right way to think about it.
> >
> > We usually call the drivers "hardened". The requirement for a hardened
> > driver is that all interactions through MMIO/port/config space IO/MSRs are
> > sanitized and do not cause memory safety issues or other information leaks.
> > Other than that there is no requirement on the functionality. In particular
> > DOS is ok since a malicious hypervisor can decide to not run the guest at
> > any time anyways.
> >
> > Someone loading an malicious driver inside the guest would be out of scope.
> > If an attacker can do that inside the guest you already violated the
> > security mechanisms and there are likely easier ways to take over the guest
> > or leak data.
> >
> > The goal of the device filter mechanism is to prevent loading unhardened
> > drivers that could be exploited without them being themselves malicious.
>
> If all you want to do is prevent someone from loading a bunch of
> drivers that you have identified as unhardened, why not just use a
> modprobe blacklist?  Am I missing something?

modules != drivers (i.e. multi-driver modules are a thing) and builtin
modules do not adhere to modprobe policy.

There is also a desire to be able to support a single kernel image
across hosts and guests. So, if you were going to say, "just compile
all unnecessary drivers as modules" that defeats the common kernel
image goal. For confidential computing the expectation is that the
necessary device set is small. As you can see in the patches in this
case it's just a few lines of PCI ids and a hack to the virtio bus to
achieve the goal of disabling all extraneous devices by default.
Andi Kleen Sept. 30, 2021, 9:12 p.m. UTC | #20
> If all you want to do is prevent someone from loading a bunch of
> drivers that you have identified as unhardened, why not just use a
> modprobe blacklist?

That wouldn't help for builtin drivers, we cannot control initcalls.

This LWN article has more details on the background.

https://lwn.net/Articles/865918/

-Andi


> Am I missing something?
>
> Alan Stern
Alan Stern Oct. 1, 2021, 1:41 a.m. UTC | #21
On Thu, Sep 30, 2021 at 01:52:59PM -0700, Dan Williams wrote:
> On Thu, Sep 30, 2021 at 1:44 PM Alan Stern <stern@rowland.harvard.edu> wrote:
> >
> > On Thu, Sep 30, 2021 at 12:23:36PM -0700, Andi Kleen wrote:
> > >
> > > > I don't think the current mitigations under discussion here are about
> > > > keeping the system working. In fact most encrypted VM configs tend to
> > > > stop booting as a preferred way to handle security issues.
> > >
> > > Maybe we should avoid the "trusted" term here. We're only really using it
> > > because USB is using it and we're now using a common framework like Greg
> > > requested. But I don't think it's the right way to think about it.
> > >
> > > We usually call the drivers "hardened". The requirement for a hardened
> > > driver is that all interactions through MMIO/port/config space IO/MSRs are
> > > sanitized and do not cause memory safety issues or other information leaks.
> > > Other than that there is no requirement on the functionality. In particular
> > > DOS is ok since a malicious hypervisor can decide to not run the guest at
> > > any time anyways.
> > >
> > > Someone loading an malicious driver inside the guest would be out of scope.
> > > If an attacker can do that inside the guest you already violated the
> > > security mechanisms and there are likely easier ways to take over the guest
> > > or leak data.
> > >
> > > The goal of the device filter mechanism is to prevent loading unhardened
> > > drivers that could be exploited without them being themselves malicious.
> >
> > If all you want to do is prevent someone from loading a bunch of
> > drivers that you have identified as unhardened, why not just use a
> > modprobe blacklist?  Am I missing something?
> 
> modules != drivers (i.e. multi-driver modules are a thing) and builtin
> modules do not adhere to modprobe policy.
> 
> There is also a desire to be able to support a single kernel image
> across hosts and guests. So, if you were going to say, "just compile
> all unnecessary drivers as modules" that defeats the common kernel
> image goal. For confidential computing the expectation is that the
> necessary device set is small. As you can see in the patches in this
> case it's just a few lines of PCI ids and a hack to the virtio bus to
> achieve the goal of disabling all extraneous devices by default.



If your goal is to prevent some unwanted _drivers_ from operating -- 
or all but a few desired drivers, as the case may be -- why extend 
the "authorized" API to all _devices_?  Why not instead develop a 
separate API (but of similar form) for drivers?

Wouldn't that make more sense?  It corresponds a lot more directly 
with what you say you want to accomplish.

What would you do in the theoretical case where two separate drivers 
can manage the same device, but one of them is desired (or hardened) 
and the other isn't?

Alan Stern
Dan Williams Oct. 1, 2021, 2:20 a.m. UTC | #22
On Thu, Sep 30, 2021 at 6:41 PM Alan Stern <stern@rowland.harvard.edu> wrote:
>
> On Thu, Sep 30, 2021 at 01:52:59PM -0700, Dan Williams wrote:
> > On Thu, Sep 30, 2021 at 1:44 PM Alan Stern <stern@rowland.harvard.edu> wrote:
> > >
> > > On Thu, Sep 30, 2021 at 12:23:36PM -0700, Andi Kleen wrote:
> > > >
> > > > > I don't think the current mitigations under discussion here are about
> > > > > keeping the system working. In fact most encrypted VM configs tend to
> > > > > stop booting as a preferred way to handle security issues.
> > > >
> > > > Maybe we should avoid the "trusted" term here. We're only really using it
> > > > because USB is using it and we're now using a common framework like Greg
> > > > requested. But I don't think it's the right way to think about it.
> > > >
> > > > We usually call the drivers "hardened". The requirement for a hardened
> > > > driver is that all interactions through MMIO/port/config space IO/MSRs are
> > > > sanitized and do not cause memory safety issues or other information leaks.
> > > > Other than that there is no requirement on the functionality. In particular
> > > > DOS is ok since a malicious hypervisor can decide to not run the guest at
> > > > any time anyways.
> > > >
> > > > Someone loading an malicious driver inside the guest would be out of scope.
> > > > If an attacker can do that inside the guest you already violated the
> > > > security mechanisms and there are likely easier ways to take over the guest
> > > > or leak data.
> > > >
> > > > The goal of the device filter mechanism is to prevent loading unhardened
> > > > drivers that could be exploited without them being themselves malicious.
> > >
> > > If all you want to do is prevent someone from loading a bunch of
> > > drivers that you have identified as unhardened, why not just use a
> > > modprobe blacklist?  Am I missing something?
> >
> > modules != drivers (i.e. multi-driver modules are a thing) and builtin
> > modules do not adhere to modprobe policy.
> >
> > There is also a desire to be able to support a single kernel image
> > across hosts and guests. So, if you were going to say, "just compile
> > all unnecessary drivers as modules" that defeats the common kernel
> > image goal. For confidential computing the expectation is that the
> > necessary device set is small. As you can see in the patches in this
> > case it's just a few lines of PCI ids and a hack to the virtio bus to
> > achieve the goal of disabling all extraneous devices by default.
>
>
>
> If your goal is to prevent some unwanted _drivers_ from operating --
> or all but a few desired drivers, as the case may be -- why extend
> the "authorized" API to all _devices_?  Why not instead develop a
> separate API (but of similar form) for drivers?
>
> Wouldn't that make more sense?  It corresponds a lot more directly
> with what you say you want to accomplish.

This was v1. v1 was NAKd [1] [2]:

[1]: https://lore.kernel.org/all/YQwpa+LAYt7YZ5dh@kroah.com/
[2]: https://lore.kernel.org/all/YQzDqm6FOezM6Rnu@kroah.com/

> What would you do in the theoretical case where two separate drivers
> can manage the same device, but one of them is desired (or hardened)
> and the other isn't?

Allow for user override, just like we do today for new_id, remove_id,
bind, and unbind  when default driver policy is insufficient.

echo 1 > /sys/bus/$bus/devices/$device/authorized
echo $device > /sys/bus/$bus/drivers/$desired_driver/bind

The device filter is really only necessary to bootstrap until you can
run override policy scripts. The driver firewall approach was overkill
in that regard.
Greg Kroah-Hartman Oct. 1, 2021, 6:29 a.m. UTC | #23
On Thu, Sep 30, 2021 at 12:15:16PM -0700, Andi Kleen wrote:
> 
> On 9/30/2021 10:23 AM, Greg Kroah-Hartman wrote:
> > On Thu, Sep 30, 2021 at 10:17:09AM -0700, Andi Kleen wrote:
> > > The legacy drivers could be fixed, but nobody really wants to touch them
> > > anymore and they're impossible to test.
> > Pointers to them?
> 
> For example if you look over old SCSI drivers in drivers/scsi/*.c there is a
> substantial number that has a module init longer than just registering a
> driver. As a single example look at drivers/scsi/BusLogic.c

Great, send patches to fix them up instead of adding new infrastructure
to the kernel.  It is better to remove code than add it.  You can rip
the ISA code out of that driver and then you will not have the issue
anymore.

Or again, just add that module to the deny list and never load it from
userspace.

> There were also quite a few platform drivers like this.

Of course, platform drivers are horrible abusers of this.  Just like the
recent one submitted by Intel that would bind to any machine it was
loaded on and did not actually do any hardware detection assuming that
it owned the platform:
	https://lore.kernel.org/r/20210924213157.3584061-2-david.e.box@linux.intel.com

So yes, some drivers are horrible, it is our job to catch that and fix
it.  If you don't want to load those drivers on your system, we have
userspace solutions for that (you can have allow/deny lists there.)

> > > The drivers that probe something that is not enumerated in a standard way
> > > have no choice, it cannot be implemented in a different way.
> > PCI devices are not enumerated in a standard way???
> 
> The pci devices are enumerated in a standard way, but typically the driver
> also needs something else outside PCI that needs some other probing
> mechanism.

Like what?  What PCI drivers need outside connections to control the
hardware?

> > > So instead we're using a "firewall" the prevents these drivers from doing
> > > bad things by not allowing ioremap access unless opted in, and also do some
> > > filtering on the IO ports The device filter is still the primary mechanism,
> > > the ioremap filtering is just belts and suspenders for those odd cases.
> > That's horrible, don't try to protect the kernel from itself.  Just fix
> > the drivers.
> 
> I thought we had already established this last time we discussed it.
> 
> That's completely impractical. We cannot harden thousands of drivers,
> especially since it would be all wasted work since nobody will ever need
> them in virtual guests. Even if we could harden them how would such a work
> be maintained long term? Using a firewall and filtering mechanism is much
> saner for everyone.

I agree, you can not "harden" anything here.  That is why I asked you to
use the existing process that explicitly moves the model to userspace
where a user can say "do I want this device to be controlled by the
kernel or not" which then allows you to pick and choose what drivers you
want to have in your system.

You need to trust devices, and not worry about trusting drivers as you
yourself admit :)

The kernel's trust model is that once we bind to them, we trust almost
all device types almost explicitly.  If you wish to change that model,
that's great, but it is a much larger discussion than this tiny patchset
would require.

thanks,

greg k-h
Alan Stern Oct. 1, 2021, 3:51 p.m. UTC | #24
On Fri, Oct 01, 2021 at 08:29:36AM +0200, Greg Kroah-Hartman wrote:
> On Thu, Sep 30, 2021 at 12:15:16PM -0700, Andi Kleen wrote:
> > 
> > On 9/30/2021 10:23 AM, Greg Kroah-Hartman wrote:
> > > On Thu, Sep 30, 2021 at 10:17:09AM -0700, Andi Kleen wrote:
> > > > The legacy drivers could be fixed, but nobody really wants to touch them
> > > > anymore and they're impossible to test.
> > > Pointers to them?
> > 
> > For example if you look over old SCSI drivers in drivers/scsi/*.c there is a
> > substantial number that has a module init longer than just registering a
> > driver. As a single example look at drivers/scsi/BusLogic.c
> 
> Great, send patches to fix them up instead of adding new infrastructure
> to the kernel.  It is better to remove code than add it.  You can rip
> the ISA code out of that driver and then you will not have the issue
> anymore.
> 
> Or again, just add that module to the deny list and never load it from
> userspace.
> 
> > There were also quite a few platform drivers like this.
> 
> Of course, platform drivers are horrible abusers of this.  Just like the
> recent one submitted by Intel that would bind to any machine it was
> loaded on and did not actually do any hardware detection assuming that
> it owned the platform:
> 	https://lore.kernel.org/r/20210924213157.3584061-2-david.e.box@linux.intel.com
> 
> So yes, some drivers are horrible, it is our job to catch that and fix
> it.  If you don't want to load those drivers on your system, we have
> userspace solutions for that (you can have allow/deny lists there.)
> 
> > > > The drivers that probe something that is not enumerated in a standard way
> > > > have no choice, it cannot be implemented in a different way.
> > > PCI devices are not enumerated in a standard way???
> > 
> > The pci devices are enumerated in a standard way, but typically the driver
> > also needs something else outside PCI that needs some other probing
> > mechanism.
> 
> Like what?  What PCI drivers need outside connections to control the
> hardware?
> 
> > > > So instead we're using a "firewall" the prevents these drivers from doing
> > > > bad things by not allowing ioremap access unless opted in, and also do some
> > > > filtering on the IO ports The device filter is still the primary mechanism,
> > > > the ioremap filtering is just belts and suspenders for those odd cases.
> > > That's horrible, don't try to protect the kernel from itself.  Just fix
> > > the drivers.
> > 
> > I thought we had already established this last time we discussed it.
> > 
> > That's completely impractical. We cannot harden thousands of drivers,
> > especially since it would be all wasted work since nobody will ever need
> > them in virtual guests. Even if we could harden them how would such a work
> > be maintained long term? Using a firewall and filtering mechanism is much
> > saner for everyone.
> 
> I agree, you can not "harden" anything here.  That is why I asked you to
> use the existing process that explicitly moves the model to userspace
> where a user can say "do I want this device to be controlled by the
> kernel or not" which then allows you to pick and choose what drivers you
> want to have in your system.
> 
> You need to trust devices, and not worry about trusting drivers as you
> yourself admit :)

That isn't the way they see it.  In their approach you can never 
trust any devices at all.  Therefore devices can only be allowed to 
bind to a very small set of "hardened" drivers.  Never mind how they 
decide whether or not a driver is sufficiently "hardened".

> The kernel's trust model is that once we bind to them, we trust almost
> all device types almost explicitly.  If you wish to change that model,
> that's great, but it is a much larger discussion than this tiny patchset
> would require.

Forget about trust for the moment.  Let's say the goal is to prevent 
the kernel from creating any bindings other that those in some small 
"allowed" set.  To fully specify one of the allowed bindings, you 
would have to provide both a device ID and a driver name.  But in 
practice this isn't necessary, since a device with a given ID will 
bind to only one driver in almost all cases, and hence giving just 
the device ID is enough.

So to do what they want, all that's needed is to forbid any bindings 
except where the device ID is "allowed".  Or to put it another way, 
where the device's authorized flag (which can be initialized based on 
the device ID) is set.

(The opposite approach, in which the drivers are "allowed" rather 
than the device IDs, apparently has already been discussed and 
rejected.  I'm not convinced that was a good decision, but...)

Does this seem like a fair description of the situation?

Alan Stern
Andi Kleen Oct. 1, 2021, 3:56 p.m. UTC | #25
> Forget about trust for the moment.  Let's say the goal is to prevent
> the kernel from creating any bindings other that those in some small
> "allowed" set.  To fully specify one of the allowed bindings, you
> would have to provide both a device ID and a driver name.  But in
> practice this isn't necessary, since a device with a given ID will
> bind to only one driver in almost all cases, and hence giving just
> the device ID is enough.
>
> So to do what they want, all that's needed is to forbid any bindings
> except where the device ID is "allowed".  Or to put it another way,
> where the device's authorized flag (which can be initialized based on
> the device ID) is set.
>
> (The opposite approach, in which the drivers are "allowed" rather
> than the device IDs, apparently has already been discussed and
> rejected.  I'm not convinced that was a good decision, but...)
>
> Does this seem like a fair description of the situation?

Yes. That's roughly what the patchkit under discussion implements.


-Andi
diff mbox series

Patch

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 68ea1f949daa..0cd03ac7d3b1 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -544,6 +544,11 @@  static int really_probe(struct device *dev, struct device_driver *drv)
 			   !drv->suppress_bind_attrs;
 	int ret;
 
+	if (!dev->authorized && !dev->bus->has_probe_authorization) {
+		dev_dbg(dev, "Device is not authorized\n");
+		return -ENODEV;
+	}
+
 	if (defer_all_probes) {
 		/*
 		 * Value of defer_all_probes can be set only by
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index 3e39686eff14..6de8a366b796 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -321,6 +321,7 @@  struct bus_type tb_bus_type = {
 	.probe = tb_service_probe,
 	.remove = tb_service_remove,
 	.shutdown = tb_service_shutdown,
+	.has_probe_authorization = true,
 };
 
 static void tb_domain_release(struct device *dev)
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index fb476665f52d..f57b5a7a90ca 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -2028,4 +2028,5 @@  struct bus_type usb_bus_type = {
 	.match =	usb_device_match,
 	.uevent =	usb_uevent,
 	.need_parent_lock =	true,
+	.has_probe_authorization = true,
 };
diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h
index 062777a45a74..571a2f6e7c1d 100644
--- a/include/linux/device/bus.h
+++ b/include/linux/device/bus.h
@@ -69,6 +69,9 @@  struct fwnode_handle;
  * @lock_key:	Lock class key for use by the lock validator
  * @need_parent_lock:	When probing or removing a device on this bus, the
  *			device core should lock the device's parent.
+ * @has_probe_authorization: Set true to indicate to the driver-core to skip
+ *			     the authorization checks and let bus drivers
+ *			     handle it locally.
  *
  * A bus is a channel between the processor and one or more devices. For the
  * purposes of the device model, all devices are connected via a bus, even if
@@ -112,6 +115,7 @@  struct bus_type {
 	struct lock_class_key lock_key;
 
 	bool need_parent_lock;
+	bool has_probe_authorization;
 };
 
 extern int __must_check bus_register(struct bus_type *bus);