Commit c7d1fd21 authored by Sebastien Bacher's avatar Sebastien Bacher

New upstream version 0.8

parents 818c656e 34905402
[flake8]
max-line-length = 120
......@@ -3,7 +3,6 @@
*~
*.log
*.xz
*.patch
# directories
build/
......
Version 0.8
-----------
_I owe it to the MM U!_
Released: 2019-06-14
* New Features:
- **IOMMU support**: adapt behavior iommu support is present and active [#128]
- automatically enroll new devices with the new `iommu` policy when iommu is active
- automatically authorize devices with the `iommu` policy if iommu is active
- `boltctl config` command to describe, get and set global, device and domain properties.
- Chain authorization and enrollment via `boltctl {enroll, authorize} --chain` [!153, !154]
- `bolt-mock` script for interactively testing `boltd` [!152]
* Improvements:
- Automatically import devices that were authorized at boot [#137]
- Make tests installable [#140]
- Honour `STATE_DIRECTORY` [!159] and `RUNTIME_DIRECTORY` [!161]
- Profiling support via gprof [!168]
* Bug fixes:
- Better handling of random data generation [#132, !165]
- Fix double free in case of client creation failure [!148]
- Fix invalid format string in warning [!14]
* NB for packagers:
- The dbus configuration is now installed in `$datadir/dbus-1/system.d` instead of `$sysconfdir` [!177].
- To install tests, configure with `-Dinstall-tests=true`.
Version 0.7
-----------
_The Known Unknowns_
Released: 2019-01-01
* Features:
- announce status to systemd via sd_notify (using a simple custom implementation) [!143]
* Bug fixes:
- properly update global security level status [#131 via !141]
- adapt to `systemd` 240 not sending `bind`/`unbind` uevents [#133 via !145]
- fix compilation on musl [#126 via !140]
- daemon: use `g_unix_signal_source…` to catch signals [#127, #129 via !138]
* Improvements
- precondition checks cleanup and completion [#124 via !139]
- error cleanup [#125, !142]
- fix some leaks and issues uncovered by coverity [!144]
Version 0.6
-----------
_Make the firmware do it!_
Released: 2018-11-28
* New Features:
- **pre-boot access control list, aka. `BootACL`** support [!119]
- domains objects are now persistent
- new `Uid` (dbus) / `uid` (object) property derived from the uuid of the device representing the root switch
- `sysfs` and `id` attribute will be set/unset on connects and disconnects
- domains are now stored in the boltd database
- domains got the `BootACL` (dbus) / `bootacl` (object) property
- uuids can be added, removed or set in batch
- when domain is *online*: changes are written to the sysfs `boot_acl` attribute directly
- when domain is *offline*: changes are written to a journal and then reapplied in order when the domain is connected
- newly enrolled devices get added to all bootacls of all domains *if* the `policy` is `BOLT_POLICY_AUTO`
- removed devices get deleted from all bootacls of all domains
- `boltacl domain` command will show the bootacl slots and their content
- `boltctl` gained the `-U, --uuid` option, to control how uuids are printed [!124]
* Improvements and fixes:
- Testing [!127]
- The test coverage increased to `84.80%` overall and to `90.0%` for the `boltd` source
- Coverage is reported for merge requests via the fedora ci image [!126]
- `boltctl` is now included in the tests [!132]
- Fedora 29 is used for the fedora ci image
- Bugs and robustness:
- The device state is verified in `Device.Authorize` [!120]
- Handle empty 'keys' sysfs device attribute [!129]
- Properly adjust policies when enrolling already authorized devices [!136]
- Fix potential crasher when logging assertions `g_return_if_fail` [!121]
Version 0.5
-----------
_You've got the Power_
Released: 2018-09-28
* New Features:
- Force-Power DBus API ⚡(!101)
- A new interface to boltd to control the (force) power mechanism (#106)
- Switch off power with a delay so we don't run into races (#104)
- Add representation of thunderbolt domains<br>
This is a preparation for the boot acl support
- Authorizing devices, after upgrading from `USER` to `SECURE` security level, will lead to key upgrades (!107)
- Connection and Authorization times are now stored (!105)
- Systemd dependency is now optional (!106, !103)
- Company and brand names are cleaned up for the display name (#102)
* Bug fixes and cleanups:
- Emit proper notification for security-level property changes (!100)
- Auto generate the object path for BoltDevice (!102)
* NB for packagers:
- `-Ddb-path` is **DEPRECATED**, use `-Ddb-name` instead (!113)
- meson >= 0.44.0 is required.
- systemd unit files got updated:
- `After=polkit.service` (!116)
- Use systemd for runtime and state directory management (!113)
- Sandbox is tightened (!97)
Version 0.4
-----------
_The Race Is Over_
Released: 2018-05-28
* New features:
- auto import of devices authorized during boot [!90]
- allow enrolling of already authorized devices, i.e. importing of devices [!86]
- label new devices and detect duplicates [!91]
* Be more robust:
- Handle NULL errors in logging code better [!89]
- Properly handle empty device database entries [!87]
- Better authentication errors and logging [!85]
- More tests
* Internal changes:
- Make sure we don't miss device status changes [!82]
- Rework property change notification dispatching [!83]
Version 0.3
-----------
_Capture The Flags_
Released: 2018-05-28
* Prepare for upcoming kernel changes:
- Support for `usbonly` (SL4) security level (#75)
- Support for `boot` sysfs device attribute (#76)
* DBus API changes:
- `BoltStatus` was split (#81), so that:
- `Device.Status` does not report `authorized-xxx` anymore
- `Device.AuthFlags` added to indicate auth details, e.g. `secure`, `nopci`, `boot`, `nokey` (#76)
- `BoltSecurity` and thus `Manager.SecurityLevel` can report `usbonly` (#75)
* client/boltctl:
- async versions for many function calls
- more efficient getters, resulting in reduced allocations
- boltctl reports `Device.AuthFlags`
- boltctl prints more and better version info via `boltctl monitor`
* Other bugfixes and improvements include:
- more robust flags/enum conversion
Version 0.2
-----------
_I broke the Bus_
Released: 2018-03-06
Lots of changes, the most significant:
- database location moved (now in `/var/lib/boltd`)
- **⚠** devices enrolled with bolt 0.1 need to be re-enrolled (or the database moved from the old location)
- DBus API changed (lots of strings)
- Enums are transmitted as strings
- `Device.Security` property is gone; replaced by `authorized-dponly` status and `Manager.SecurityLevel` ( #37, #38, #62)
- Various timestamps got added: `Device.ConnectTime`, `Device.StoreTime` and `Device.AuthorizeTime` (#46 #57)
- `Device.Label` (readwrite) was added so devices can be given custom names (#46)
- `Device.Type` added, to differentiate between host and peripherals
- `Manager.AuthMode` (readwrite) was added to control (auto) authorization (#48)
Other bugfixes and improvements include:
- Ensure we get a `DeviceAdded` signal on startup (#58)
- Support for legacy devices that have no key sysfs attribute (#67)
- Use structured logging and avoid printing UUIDs in non-debug log code (#36 #60)
- Other internal restructuring for cleaner code (#43)
Version 0.1
-----------
_Accidentally Working_
Released: 2017-12-13
* functional daemon that can authorize enroll and authorize devices
* `boltctl` command to interact with the daemon
Patches
=======
Patches should be submitted in the form of pull requests at
[github][github].
Patches should be submitted in the form of merge requests at
[gitlab][gitlab].
Coding style
......@@ -64,7 +64,7 @@ must be in `PATH`) from the source directory:
Upload the `bolt.xz` file to coverity for analysis. Fix defects. Profit.
[github]: https://github.com/gicmo/bolt
[gitlab]: https://gitlab.freedesktop.org/bolt/bolt
[coverity]: https://scan.coverity.com/projects/bolt
[cov-build]: https://scan.coverity.com/download
[valgrind]: https://gist.github.com/gicmo/327dad149fcb386ac7f59e279b8ba322
......@@ -44,7 +44,10 @@ The core of bolt is a system daemon (`boltd`) that interfaces with
sysfs and exposes devices via D-Bus to clients. It also has a database
of previously authorized devices (and their keys) and will, depending
on the policy set for the individual devices, automatically authorize
newly connected devices without user interaction.
newly connected devices without user interaction. The daemon supports
syncing the devices database with the pre-boot access control list
firmware feature. It also adapts its behavior when iommu support is
detected.
boltctl - command line client
-----------------------------
......
......@@ -44,6 +44,9 @@ struct _BoltAuth
/* result */
GError *error;
/* memory for enrollment */
BoltPolicy policy;
};
......@@ -57,6 +60,8 @@ enum {
PROP_DEVICE,
PROP_ERROR,
PROP_POLICY,
PROP_LAST
};
......@@ -111,6 +116,10 @@ bolt_auth_get_property (GObject *object,
g_value_set_object (value, auth->dev);
break;
case PROP_POLICY:
g_value_set_enum (value, auth->policy);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
......@@ -143,6 +152,10 @@ bolt_auth_set_property (GObject *object,
auth->dev = g_value_dup_object (value);
break;
case PROP_POLICY:
auth->policy = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
......@@ -196,6 +209,15 @@ bolt_auth_class_init (BoltAuthClass *klass)
G_PARAM_READWRITE |
G_PARAM_STATIC_NICK);
props[PROP_POLICY] =
g_param_spec_enum ("policy",
NULL, NULL,
BOLT_TYPE_POLICY,
BOLT_POLICY_UNKNOWN,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class,
PROP_LAST,
props);
......@@ -297,6 +319,13 @@ bolt_auth_check (BoltAuth *auth,
return TRUE;
}
BoltDevice *
bolt_auth_get_device (BoltAuth *auth)
{
g_return_val_if_fail (BOLT_IS_AUTH (auth), NULL);
return auth->dev;
}
BoltSecurity
bolt_auth_get_level (BoltAuth *auth)
......@@ -322,6 +351,14 @@ bolt_auth_get_keystate (BoltAuth *auth)
return bolt_key_get_state (auth->key);
}
gboolean
bolt_auth_has_key (BoltAuth *auth)
{
g_return_val_if_fail (BOLT_IS_AUTH (auth), FALSE);
return auth->key != NULL;
}
gpointer
bolt_auth_get_origin (BoltAuth *auth)
{
......@@ -330,6 +367,27 @@ bolt_auth_get_origin (BoltAuth *auth)
return auth->origin;
}
BoltPolicy
bolt_auth_get_policy (BoltAuth *auth)
{
g_return_val_if_fail (BOLT_IS_AUTH (auth), BOLT_POLICY_UNKNOWN);
return auth->policy;
}
void
bolt_auth_set_policy (BoltAuth *auth,
BoltPolicy policy)
{
g_return_if_fail (BOLT_IS_AUTH (auth));
if (auth->policy == policy)
return;
auth->policy = policy;
g_object_notify_by_pspec (G_OBJECT (auth), props[PROP_POLICY]);
}
BoltStatus
bolt_auth_to_status (BoltAuth *auth)
{
......
......@@ -27,6 +27,9 @@
G_BEGIN_DECLS
/* forward decl because bolt-device.h include bolt-auth.h */
typedef struct _BoltDevice BoltDevice;
#define BOLT_TYPE_AUTH bolt_auth_get_type ()
G_DECLARE_FINAL_TYPE (BoltAuth, bolt_auth, BOLT, AUTH, GObject);
......@@ -46,14 +49,23 @@ void bolt_auth_return_error (BoltAuth *auth,
gboolean bolt_auth_check (BoltAuth *auth,
GError **error);
BoltDevice * bolt_auth_get_device (BoltAuth *auth);
BoltSecurity bolt_auth_get_level (BoltAuth *auth);
BoltKey * bolt_auth_get_key (BoltAuth *auth);
BoltKeyState bolt_auth_get_keystate (BoltAuth *auth);
gboolean bolt_auth_has_key (BoltAuth *auth);
gpointer bolt_auth_get_origin (BoltAuth *auth);
BoltPolicy bolt_auth_get_policy (BoltAuth *auth);
void bolt_auth_set_policy (BoltAuth *auth,
BoltPolicy policy);
BoltStatus bolt_auth_to_status (BoltAuth *auth);
BoltAuthFlags bolt_auth_to_flags (BoltAuth *auth,
......
......@@ -22,6 +22,7 @@
#include "bolt-enums.h"
#include "bolt-error.h"
#include "bolt-names.h"
#include "bolt-config.h"
......@@ -31,6 +32,39 @@
#define DEFAULT_POLICY_KEY "DefaultPolicy"
#define AUTH_MODE_KEY "AuthMode"
const char *
bolt_get_store_path (void)
{
const char *path;
/* set by tools or the user directly */
path = g_getenv (BOLT_ENV_DBPATH);
if (path != NULL)
return path;
/* set by systemd >= 240 to an absolute path
* taking into account the StateDirectory
* unit file setting */
path = g_getenv (BOLT_ENV_STATE_DIRECTORY);
if (path != NULL)
return path;
/* set at compile time (config.h) */
return BOLT_DBDIR;
}
const char *
bolt_get_runtime_directory (void)
{
const char *path;
path = g_getenv (BOLT_ENV_RUNTIME_DIRECTORY);
if (path)
return path;
return "/run/boltd";
}
GKeyFile *
bolt_config_user_init (void)
{
......
......@@ -26,6 +26,12 @@
G_BEGIN_DECLS
/* well known paths */
const char * bolt_get_store_path (void);
const char * bolt_get_runtime_directory (void);
/* user and system configuration */
typedef enum BoltTri {
TRI_ERROR = -1,
......
......@@ -20,14 +20,13 @@
#include "config.h"
#include "bolt-dbus.h"
#include "bolt-log.h"
#include "bolt-manager.h"
#include "bolt-names.h"
#include "bolt-str.h"
#include "bolt-term.h"
#include "bolt-daemon-resource.h"
#include <glib-unix.h>
#include <gio/gio.h>
......@@ -228,7 +227,7 @@ main (int argc, char **argv)
bolt_log_gen_id (log.session_id);
g_resources_register (bolt_daemon_get_resource ());
bolt_dbus_ensure_resources ();
bolt_msg (LOG_DIRECT (BOLT_LOG_VERSION, PACKAGE_VERSION),
LOG_ID (STARTUP),
......
......@@ -25,6 +25,7 @@
#include "bolt-domain.h"
#include "bolt-enums.h"
#include "bolt-error.h"
#include "bolt-glue.h"
#include "bolt-io.h"
#include "bolt-log.h"
#include "bolt-manager.h"
......@@ -509,7 +510,7 @@ bolt_device_class_init (BoltDeviceClass *klass)
bolt_exported_class_set_interface_info (exported_class,
BOLT_DBUS_DEVICE_INTERFACE,
"/boltd/org.freedesktop.bolt.xml");
BOLT_DBUS_GRESOURCE_PATH);
bolt_exported_class_set_object_path (exported_class,
BOLT_DBUS_PATH_DEVICES);
......@@ -1016,7 +1017,7 @@ handle_authorize_done (GObject *device,
}
static gboolean
device_should_uprade_key (BoltDevice *dev)
device_should_upgrade_key (BoltDevice *dev)
{
gboolean upgrade = FALSE;
const char *reason = NULL;
......@@ -1041,9 +1042,9 @@ handle_authorize (BoltExported *object,
GError **error)
{
g_autoptr(BoltAuth) auth = NULL;
g_autoptr(BoltKey) key = NULL;
BoltDevice *dev = BOLT_DEVICE (object);
BoltSecurity level;
BoltKey *key;
/* In bolt_device_authorize the state is also checked, but it
* is done already here to fail quicker and avoid accessing the
......@@ -1065,19 +1066,20 @@ handle_authorize (BoltExported *object,
}
level = bolt_domain_get_security (dev->domain);
key = NULL;
if (level == BOLT_SECURITY_SECURE)
{
if (dev->key)
key = bolt_store_get_key (dev->store, dev->uid, error);
else if (device_should_uprade_key (dev))
key = bolt_key_new ();
else if (device_should_upgrade_key (dev))
key = bolt_key_new (error);
else
level = BOLT_SECURITY_USER;
}
/* only happens if the key could not be read */
/* happens if the key could not be read (fatal error) or if a new
* key could not be generated (should practically never happen).
* In both cases 'error' will be set. */
if (level == BOLT_SECURITY_SECURE && key == NULL)
return NULL;
......@@ -1439,6 +1441,26 @@ bolt_device_get_stored (BoltDevice *dev)
return dev->store != NULL;
}
gboolean
bolt_device_has_iommu (BoltDevice *dev)
{
g_return_val_if_fail (BOLT_IS_DEVICE (dev), FALSE);
if (dev->domain == NULL)
return FALSE;
return bolt_domain_has_iommu (dev->domain);
}
gboolean
bolt_device_has_key (BoltDevice *dev)
{
g_return_val_if_fail (BOLT_IS_DEVICE (dev), FALSE);
return !(dev->key == BOLT_KEY_UNKNOWN ||
dev->key == BOLT_KEY_MISSING);
}
const char *
bolt_device_get_syspath (BoltDevice *dev)
{
......@@ -1544,3 +1566,29 @@ bolt_device_get_key_from_sysfs (BoltDevice *dev,
else
return bolt_error_propagate (error, &err);
}
gboolean
bolt_device_load_key (BoltDevice *dev,
BoltKey **key,
GError **error)
{
BoltKey *k;
g_return_val_if_fail (BOLT_IS_DEVICE (dev), FALSE);
g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (!bolt_device_has_key (dev) || dev->store == NULL)
{
*key = NULL;
return TRUE;
}
k = bolt_store_get_key (dev->store, dev->uid, error);
if (k == NULL)
return FALSE;
*key = k;
return TRUE;
}
......@@ -98,6 +98,10 @@ guint64 bolt_device_get_conntime (BoltDevice *dev);
gint64 bolt_device_get_storetime (BoltDevice *dev);
gboolean bolt_device_has_iommu (BoltDevice *dev);
gboolean bolt_device_has_key (BoltDevice *dev);
gboolean bolt_device_supports_secure_mode (BoltDevice *dev);
gboolean bolt_device_check_authflag (BoltDevice *dev,
......@@ -106,6 +110,8 @@ gboolean bolt_device_check_authflag (BoltDevice *dev,
gboolean bolt_device_get_key_from_sysfs (BoltDevice *dev,
BoltKey **key,
GError **error);
gboolean bolt_device_load_key (BoltDevice *dev,
BoltKey **key,
GError **error);
G_END_DECLS
......@@ -21,6 +21,7 @@
#include "config.h"
#include "bolt-error.h"
#include "bolt-glue.h"
#include "bolt-log.h"
#include "bolt-str.h"
#include "bolt-store.h"
......@@ -54,6 +55,7 @@ struct _BoltDomain
char *syspath;
BoltSecurity security;
GStrv bootacl;
gboolean iommu;
};
......@@ -70,6 +72,7 @@ enum {
PROP_SYSPATH,
PROP_SECURITY,
PROP_BOOTACL,
PROP_IOMMU,
PROP_LAST,
PROP_EXPORTED = PROP_UID
......@@ -146,6 +149,10 @@ bolt_domain_get_property (GObject *object,
g_value_set_boxed (value, dom->bootacl);
break;
case PROP_IOMMU:
g_value_set_boolean (value, dom->iommu);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
......@@ -197,6 +204,10 @@ bolt_domain_set_property (GObject *object,
dom->bootacl = g_value_dup_boxed (value);
break;
case PROP_IOMMU:
dom->iommu = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
......@@ -263,13 +274,21 @@ bolt_domain_class_init (BoltDomainClass *klass)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
props[PROP_IOMMU] =
g_param_spec_boolean ("iommu",
"IOMMU", NULL,
FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class,
PROP_LAST,
props);
bolt_exported_class_set_interface_info (exported_class,
BOLT_DBUS_DOMAIN_INTERFACE,
"/boltd/org.freedesktop.bolt.xml");
BOLT_DBUS_GRESOURCE_PATH);
bolt_exported_class_set_object_path (exported_class, BOLT_DBUS_PATH_DOMAINS);
......@@ -542,6 +561,7 @@ bolt_domain_new_for_udev (struct udev_device *udev,
BoltSecurity security = BOLT_SECURITY_UNKNOWN;
const char *syspath;
const char *sysname;
gboolean iommu;
gboolean ok;
gint sort = -1;
......@@ -565,7 +585,7 @@ bolt_domain_new_for_udev (struct udev_device *udev,
if (g_str_has_prefix (sysname, "domain"))
{
const char *ptr = sysname + strlen ("domain");
bolt_str_parse_as_int (ptr, &sort);
bolt_str_parse_as_int (ptr, &sort, NULL);
}
security = bolt_sysfs_security_for_device (udev, error);
......@@ -575,7 +595,19 @@ bolt_domain_new_for_udev (struct udev_device *udev,
ok = bolt_sysfs_read_boot_acl (udev, &acl, &err);
if (!ok)
bolt_warn_err (err, "failed to get boot_acl");
{
bolt_warn_err (err, LOG_TOPIC ("udev"),
"failed to read boot_acl");
g_clear_error (&err);
}
ok = bolt_sysfs_read_iommu (udev, &iommu, &err);
if (!ok)
{
bolt_warn_err (err, LOG_TOPIC ("udev"),
"failed to read iommu");
g_clear_error (&err);
}
dom = g_object_new (BOLT_TYPE_DOMAIN,
"uid", uid,
......@@ -583,6 +615,7 @@ bolt_domain_new_for_udev (struct udev_device *udev,
"syspath", syspath,
"security", security,
"bootacl", acl,
"iommu", iommu,
NULL);
return dom;
......@@ -652,6 +685,14 @@ bolt_domain_is_connected (BoltDomain *domain)
return domain->syspath != NULL;
}
gboolean
bolt_domain_has_iommu (BoltDomain *domain)
{
g_return_val_if_fail (BOLT_IS_DOMAIN (domain), FALSE);
return domain->iommu;
}
void
bolt_domain_export (BoltDomain *domain,
GDBusConnection *bus)
......@@ -687,6 +728,7 @@ bolt_domain_connected (BoltDomain *domain,
BoltSecurity security;
const char *syspath;
const char *id;
gboolean iommu;
gboolean ok;
g_return_if_fail (BOLT_IS_DOMAIN (domain));
......@@ -714,15 +756,25 @@ bolt_do