From f5f5ed83af7223b2f5ddc1f829bc7ff0acb8db0d Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 9 Aug 2018 14:38:34 +0200 Subject: [PATCH 1/7] Bump version 126 --- hassio/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/const.py b/hassio/const.py index 376f2c99f..7efdb85f3 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -2,7 +2,7 @@ from pathlib import Path from ipaddress import ip_network -HASSIO_VERSION = '125' +HASSIO_VERSION = '126' URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons" URL_HASSIO_VERSION = \ From 640d66ad1acd6e6b6bdca8d646b2a7eaaa71b164 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 15 Aug 2018 21:38:57 +0200 Subject: [PATCH 2/7] Update uvloop 0.11.2 (#648) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 31e80730b..682407fe8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,5 +9,5 @@ pytz==2018.4 pyudev==0.21.0 pycryptodome==3.6.4 cpe==1.2.1 -uvloop==0.11.1 +uvloop==0.11.2 cchardet==2.1.1 From 087f7466477d1c6a90b554e7514546f7c8a7de03 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 15 Aug 2018 22:05:13 +0200 Subject: [PATCH 3/7] update docker API to 3.5.0 (#650) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 682407fe8..32ebcdc4f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ attr==0.3.1 async_timeout==3.0.0 aiohttp==3.3.2 -docker==3.4.1 +docker==3.5.0 colorlog==3.1.2 voluptuous==0.11.5 gitpython==2.1.10 From 0d4a808449b023895e5f0312abb403d499d656be Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 15 Aug 2018 23:52:52 +0200 Subject: [PATCH 4/7] Improve docker build cache for supervisor (#651) --- Dockerfile | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 96d6ef136..8c9e55bdd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,17 @@ ARG BUILD_FROM FROM $BUILD_FROM -# Setup base +# Install base +apk add --no-cache \ + git \ + socat \ + glib \ + libstdc++ \ + eudev-libs + +# Install requirements COPY requirements.txt /usr/src/ -RUN apk add --no-cache \ - git \ - socat \ - glib \ - libstdc++ \ - eudev-libs \ - && apk add --no-cache --virtual .build-dependencies \ +RUN apk add --no-cache --virtual .build-dependencies \ make \ g++ \ && pip3 install --no-cache-dir -r /usr/src/requirements.txt \ From 6e6c2c3efb4ae64a5dcbce1572a308e0a667245e Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 16 Aug 2018 01:40:20 +0200 Subject: [PATCH 5/7] Change timezone handling (#641) * Change timezone handling * Update dt.py * Update homeassistant.py * fix * Use new timezone * fix handling * fix regex * fix regex * Rename old config * fix lint * simplify * fix regex * fix * cleanup * cleanup * fix * fix find * mm --- hassio/bootstrap.py | 7 ++++--- hassio/config.py | 25 ++++++++++++++++++++++--- hassio/coresys.py | 5 +++++ hassio/docker/addon.py | 4 ++-- hassio/docker/homeassistant.py | 8 ++++---- hassio/utils/dt.py | 1 - 6 files changed, 37 insertions(+), 13 deletions(-) diff --git a/hassio/bootstrap.py b/hassio/bootstrap.py index 1d661f752..9773d04d8 100644 --- a/hassio/bootstrap.py +++ b/hassio/bootstrap.py @@ -66,10 +66,11 @@ def initialize_system_data(coresys): config = coresys.config # homeassistant config folder - if not config.path_config.is_dir(): + if not config.path_homeassistant.is_dir(): _LOGGER.info( - "Create Home-Assistant config folder %s", config.path_config) - config.path_config.mkdir() + "Create Home-Assistant config folder %s", + config.path_homeassistant) + config.path_homeassistant.mkdir() # hassio ssl folder if not config.path_ssl.is_dir(): diff --git a/hassio/config.py b/hassio/config.py index 6f1aafd5a..c4198352d 100644 --- a/hassio/config.py +++ b/hassio/config.py @@ -2,8 +2,11 @@ from datetime import datetime import logging import os +import re from pathlib import Path, PurePath +import pytz + from .const import ( FILE_HASSIO_CONFIG, HASSIO_DATA, ATTR_TIMEZONE, ATTR_ADDONS_CUSTOM_LIST, ATTR_LAST_BOOT, ATTR_WAIT_BOOT) @@ -29,6 +32,8 @@ APPARMOR_DATA = PurePath("apparmor") DEFAULT_BOOT_TIME = datetime.utcfromtimestamp(0).isoformat() +RE_TIMEZONE = re.compile(r"time_zone: (?P[\w/\-+]+)") + class CoreConfig(JsonConfig): """Hold all core config data.""" @@ -40,7 +45,21 @@ class CoreConfig(JsonConfig): @property def timezone(self): """Return system timezone.""" - return self._data[ATTR_TIMEZONE] + config_file = Path(self.path_homeassistant, 'configuration.yaml') + try: + assert config_file.exists() + configuration = config_file.read_text() + + data = RE_TIMEZONE.search(configuration) + assert data + + timezone = data.group('timezone') + pytz.timezone(timezone) + except (pytz.exceptions.UnknownTimeZoneError, OSError, AssertionError): + _LOGGER.debug("Can't parse HomeAssistant timezone") + return self._data[ATTR_TIMEZONE] + + return timezone @timezone.setter def timezone(self, value): @@ -83,12 +102,12 @@ class CoreConfig(JsonConfig): return PurePath(os.environ['SUPERVISOR_SHARE']) @property - def path_extern_config(self): + def path_extern_homeassistant(self): """Return config path extern for docker.""" return str(PurePath(self.path_extern_hassio, HOMEASSISTANT_CONFIG)) @property - def path_config(self): + def path_homeassistant(self): """Return config path inside supervisor.""" return Path(HASSIO_DATA, HOMEASSISTANT_CONFIG) diff --git a/hassio/coresys.py b/hassio/coresys.py index af00041d9..5e27edd36 100644 --- a/hassio/coresys.py +++ b/hassio/coresys.py @@ -66,6 +66,11 @@ class CoreSys: """Return True if we run dev modus.""" return self._updater.channel == CHANNEL_DEV + @property + def timezone(self): + """Return timezone.""" + return self._config.timezone + @property def loop(self): """Return loop object.""" diff --git a/hassio/docker/addon.py b/hassio/docker/addon.py index 1b858dbbe..260a4e9ca 100644 --- a/hassio/docker/addon.py +++ b/hassio/docker/addon.py @@ -86,7 +86,7 @@ class DockerAddon(DockerInterface): return { **addon_env, - ENV_TIME: self.sys_config.timezone, + ENV_TIME: self.sys_timezone, ENV_TOKEN: self.addon.uuid, } @@ -173,7 +173,7 @@ class DockerAddon(DockerInterface): # setup config mappings if MAP_CONFIG in addon_mapping: volumes.update({ - str(self.sys_config.path_extern_config): { + str(self.sys_config.path_extern_homeassistant): { 'bind': "/config", 'mode': addon_mapping[MAP_CONFIG] }}) diff --git a/hassio/docker/homeassistant.py b/hassio/docker/homeassistant.py index 4a85a3493..ea54f00cf 100644 --- a/hassio/docker/homeassistant.py +++ b/hassio/docker/homeassistant.py @@ -61,11 +61,11 @@ class DockerHomeAssistant(DockerInterface): network_mode='host', environment={ 'HASSIO': self.sys_docker.network.supervisor, - ENV_TIME: self.sys_config.timezone, + ENV_TIME: self.sys_timezone, ENV_TOKEN: self.sys_homeassistant.uuid, }, volumes={ - str(self.sys_config.path_extern_config): + str(self.sys_config.path_extern_homeassistant): {'bind': '/config', 'mode': 'rw'}, str(self.sys_config.path_extern_ssl): {'bind': '/ssl', 'mode': 'ro'}, @@ -95,10 +95,10 @@ class DockerHomeAssistant(DockerInterface): stdout=True, stderr=True, environment={ - ENV_TIME: self.sys_config.timezone, + ENV_TIME: self.sys_timezone, }, volumes={ - str(self.sys_config.path_extern_config): + str(self.sys_config.path_extern_homeassistant): {'bind': '/config', 'mode': 'rw'}, str(self.sys_config.path_extern_ssl): {'bind': '/ssl', 'mode': 'ro'}, diff --git a/hassio/utils/dt.py b/hassio/utils/dt.py index c5ff11316..5a3a1825d 100644 --- a/hassio/utils/dt.py +++ b/hassio/utils/dt.py @@ -9,7 +9,6 @@ UTC = pytz.utc _LOGGER = logging.getLogger(__name__) -FREEGEOIP_URL = "https://freegeoip.net/json/" # Copyright (c) Django Software Foundation and individual contributors. # All rights reserved. From 85fbde8e364d4379f57eeb345bc60f466f6ce423 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 16 Aug 2018 01:42:56 +0200 Subject: [PATCH 6/7] Fix Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8c9e55bdd..8726b94ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ ARG BUILD_FROM FROM $BUILD_FROM # Install base -apk add --no-cache \ +RUN apk add --no-cache \ git \ socat \ glib \ From ecd12732eeb41b6a9cfc24e0775d12fb7a107a50 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 16 Aug 2018 22:49:08 +0200 Subject: [PATCH 7/7] New generation of security and access (#652) * New generation of security and access * Update const.py * Update validate.py * Update addon.py * Update validate.py * Fix name * Allow access * Fix * add logs * change message * add rating * fix lint * fix lint * fix * Fix --- API.md | 4 ++++ hassio/addons/addon.py | 24 +++++++++++++++++++++--- hassio/addons/utils.py | 38 ++++++++++++++++++++++++++++++++++++++ hassio/addons/validate.py | 22 ++++++++++++++-------- hassio/api/addons.py | 19 +++++++++++++++++-- hassio/api/utils.py | 4 ++-- hassio/const.py | 11 +++++++++++ hassio/docker/addon.py | 13 ++++++++++++- hassio/exceptions.py | 13 +++++++++++++ 9 files changed, 132 insertions(+), 16 deletions(-) diff --git a/API.md b/API.md index de8aca967..e0bb0159b 100644 --- a/API.md +++ b/API.md @@ -478,6 +478,9 @@ Get all available addons. "changelog": "bool", "hassio_api": "bool", "homeassistant_api": "bool", + "full_access": "bool", + "protected": "bool", + "rating": "1-5", "stdin": "bool", "webui": "null|http(s)://[HOST]:port/xy/zx", "gpio": "bool", @@ -507,6 +510,7 @@ Get all available addons. "CONTAINER": "port|[ip, port]" }, "options": {}, + "protected": "bool", "audio_output": "null|0,0", "audio_input": "null|0,0" } diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index 6dac66d0d..103d1bed4 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -25,8 +25,9 @@ from ..const import ( ATTR_HASSIO_API, ATTR_AUDIO, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY, ATTR_HOST_IPC, ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_DISCOVERY, ATTR_SERVICES, - ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API, SECURITY_PROFILE, - SECURITY_DISABLE, SECURITY_DEFAULT) + ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API, ATTR_FULL_ACCESS, + ATTR_PROTECTED, + SECURITY_PROFILE, SECURITY_DISABLE, SECURITY_DEFAULT) from ..coresys import CoreSysAttributes from ..docker.addon import DockerAddon from ..utils.json import write_json_file, read_json_file @@ -201,6 +202,18 @@ class Addon(CoreSysAttributes): return self._data.cache[self._id][ATTR_VERSION] return self.version_installed + @property + def protected(self): + """Return if addon is in protected mode.""" + if self.is_installed: + return self._data.user[self._id][ATTR_PROTECTED] + return True + + @protected.setter + def protected(self, value): + """Set addon in protected mode.""" + self._data.user[self._id][ATTR_PROTECTED] = value + @property def startup(self): """Return startup type of addon.""" @@ -336,7 +349,7 @@ class Addon(CoreSysAttributes): return self._mesh.get(ATTR_LEGACY) @property - def with_docker_api(self): + def access_docker_api(self): """Return if the add-on need read-only docker API access.""" return self._mesh.get(ATTR_DOCKER_API) @@ -360,6 +373,11 @@ class Addon(CoreSysAttributes): """Return True if the add-on access to gpio interface.""" return self._mesh[ATTR_GPIO] + @property + def with_full_access(self): + """Return True if the add-on want full access to hardware.""" + return self._mesh[ATTR_FULL_ACCESS] + @property def with_devicetree(self): """Return True if the add-on read access to devicetree.""" diff --git a/hassio/addons/utils.py b/hassio/addons/utils.py index c876312d0..27c393f09 100644 --- a/hassio/addons/utils.py +++ b/hassio/addons/utils.py @@ -4,11 +4,49 @@ import hashlib import logging import re +from ..const import ( + SECURITY_DISABLE, SECURITY_PROFILE, PRIVILEGED_NET_ADMIN, + PRIVILEGED_SYS_ADMIN, PRIVILEGED_SYS_RAWIO) + RE_SHA1 = re.compile(r"[a-f0-9]{8}") _LOGGER = logging.getLogger(__name__) +def rating_security(addon): + """Return 1-5 for security rating. + + 1 = not secure + 5 = high secure + """ + rating = 4 + + # AppArmor + if addon.apparmor == SECURITY_DISABLE: + rating += -1 + elif addon.apparmor == SECURITY_PROFILE: + rating += 1 + + # API Access + if addon.access_hassio_api or addon.access_homeassistant_api: + rating += -1 + + # Privileged options + if addon.privileged in (PRIVILEGED_NET_ADMIN, PRIVILEGED_SYS_ADMIN, + PRIVILEGED_SYS_RAWIO): + rating += -1 + + # Full Access + if addon.with_full_access: + rating += -2 + + # Docker Access + if addon.access_docker_api: + rating = 1 + + return max(min(5, rating), 1) + + def get_hash_from_repository(name): """Generate a hash from repository.""" key = name.lower().encode() diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index 008ad3fb1..d5881bead 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -18,7 +18,11 @@ from ..const import ( ATTR_AUDIO_OUTPUT, ATTR_HASSIO_API, ATTR_BUILD_FROM, ATTR_SQUASH, ATTR_ARGS, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY, ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_SERVICES, ATTR_DISCOVERY, - ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API) + ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API, ATTR_PROTECTED, + ATTR_FULL_ACCESS, + PRIVILEGED_NET_ADMIN, PRIVILEGED_SYS_ADMIN, PRIVILEGED_SYS_RAWIO, + PRIVILEGED_IPC_LOCK, PRIVILEGED_SYS_TIME, PRIVILEGED_SYS_NICE, + PRIVILEGED_SYS_RESOURCE) from ..validate import NETWORK_PORT, DOCKER_PORTS, ALSA_DEVICE _LOGGER = logging.getLogger(__name__) @@ -58,13 +62,13 @@ STARTUP_ALL = [ ] PRIVILEGED_ALL = [ - "NET_ADMIN", - "SYS_ADMIN", - "SYS_RAWIO", - "IPC_LOCK", - "SYS_TIME", - "SYS_NICE", - "SYS_RESOURCE" + PRIVILEGED_NET_ADMIN, + PRIVILEGED_SYS_ADMIN, + PRIVILEGED_SYS_RAWIO, + PRIVILEGED_IPC_LOCK, + PRIVILEGED_SYS_TIME, + PRIVILEGED_SYS_NICE, + PRIVILEGED_SYS_RESOURCE, ] BASE_IMAGE = { @@ -110,6 +114,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)}, vol.Optional(ATTR_PRIVILEGED): [vol.In(PRIVILEGED_ALL)], vol.Optional(ATTR_APPARMOR, default=True): vol.Boolean(), + vol.Optional(ATTR_FULL_ACCESS, default=False): vol.Boolean(), vol.Optional(ATTR_AUDIO, default=False): vol.Boolean(), vol.Optional(ATTR_GPIO, default=False): vol.Boolean(), vol.Optional(ATTR_DEVICETREE, default=False): vol.Boolean(), @@ -170,6 +175,7 @@ SCHEMA_ADDON_USER = vol.Schema({ vol.Optional(ATTR_NETWORK): DOCKER_PORTS, vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_DEVICE, vol.Optional(ATTR_AUDIO_INPUT): ALSA_DEVICE, + vol.Optional(ATTR_PROTECTED, default=True): vol.Boolean(), }, extra=vol.REMOVE_EXTRA) diff --git a/hassio/api/addons.py b/hassio/api/addons.py index 12fcc732b..927271ddb 100644 --- a/hassio/api/addons.py +++ b/hassio/api/addons.py @@ -6,6 +6,7 @@ import voluptuous as vol from voluptuous.humanize import humanize_error from .utils import api_process, api_process_raw, api_validate +from ..addons.utils import rating_security from ..const import ( ATTR_VERSION, ATTR_LAST_VERSION, ATTR_STATE, ATTR_BOOT, ATTR_OPTIONS, ATTR_URL, ATTR_DESCRIPTON, ATTR_DETACHED, ATTR_NAME, ATTR_REPOSITORY, @@ -18,9 +19,11 @@ from ..const import ( ATTR_CPU_PERCENT, ATTR_MEMORY_LIMIT, ATTR_MEMORY_USAGE, ATTR_NETWORK_TX, ATTR_NETWORK_RX, ATTR_BLK_READ, ATTR_BLK_WRITE, ATTR_ICON, ATTR_SERVICES, ATTR_DISCOVERY, ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API, - CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT) + ATTR_FULL_ACCESS, ATTR_PROTECTED, ATTR_RATING, + CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT, REQUEST_FROM) from ..coresys import CoreSysAttributes from ..validate import DOCKER_PORTS, ALSA_DEVICE +from ..exceptions import APINotSupportedError _LOGGER = logging.getLogger(__name__) @@ -35,6 +38,7 @@ SCHEMA_OPTIONS = vol.Schema({ vol.Optional(ATTR_AUTO_UPDATE): vol.Boolean(), vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_DEVICE, vol.Optional(ATTR_AUDIO_INPUT): ALSA_DEVICE, + vol.Optional(ATTR_PROTECTED): vol.Boolean(), }) @@ -116,6 +120,8 @@ class APIAddons(CoreSysAttributes): ATTR_REPOSITORY: addon.repository, ATTR_LAST_VERSION: addon.last_version, ATTR_STATE: await addon.state(), + ATTR_PROTECTED: addon.protected, + ATTR_RATING: rating_security(addon), ATTR_BOOT: addon.boot, ATTR_OPTIONS: addon.options, ATTR_URL: addon.url, @@ -126,6 +132,7 @@ class APIAddons(CoreSysAttributes): ATTR_HOST_IPC: addon.host_ipc, ATTR_HOST_DBUS: addon.host_dbus, ATTR_PRIVILEGED: addon.privileged, + ATTR_FULL_ACCESS: addon.with_full_access, ATTR_APPARMOR: addon.apparmor, ATTR_DEVICES: self._pretty_devices(addon), ATTR_ICON: addon.with_icon, @@ -137,7 +144,7 @@ class APIAddons(CoreSysAttributes): ATTR_HOMEASSISTANT_API: addon.access_homeassistant_api, ATTR_GPIO: addon.with_gpio, ATTR_DEVICETREE: addon.with_devicetree, - ATTR_DOCKER_API: addon.with_docker_api, + ATTR_DOCKER_API: addon.access_docker_api, ATTR_AUDIO: addon.with_audio, ATTR_AUDIO_INPUT: addon.audio_input, ATTR_AUDIO_OUTPUT: addon.audio_output, @@ -150,6 +157,11 @@ class APIAddons(CoreSysAttributes): """Store user options for addon.""" addon = self._extract_addon(request) + # Have Access + if addon.slug == request[REQUEST_FROM]: + _LOGGER.error("Add-on can't self modify his options!") + raise APINotSupportedError() + addon_schema = SCHEMA_OPTIONS.extend({ vol.Optional(ATTR_OPTIONS): vol.Any(None, addon.schema), }) @@ -168,6 +180,9 @@ class APIAddons(CoreSysAttributes): addon.audio_input = body[ATTR_AUDIO_INPUT] if ATTR_AUDIO_OUTPUT in body: addon.audio_output = body[ATTR_AUDIO_OUTPUT] + if ATTR_PROTECTED in body: + _LOGGER.warning("Protected flag changing for %s!", addon.slug) + addon.protected = body[ATTR_PROTECTED] addon.save_data() return True diff --git a/hassio/api/utils.py b/hassio/api/utils.py index b3ce8a4db..f4f5f9e32 100644 --- a/hassio/api/utils.py +++ b/hassio/api/utils.py @@ -30,10 +30,10 @@ def api_process(method): """Return api information.""" try: answer = await method(api, *args, **kwargs) - except RuntimeError as err: - return api_return_error(message=str(err)) except HassioError: return api_return_error() + except RuntimeError as err: + return api_return_error(message=str(err)) if isinstance(answer, dict): return api_return_ok(data=answer) diff --git a/hassio/const.py b/hassio/const.py index 7efdb85f3..1a28061f9 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -179,6 +179,9 @@ ATTR_VERSION_CLI = 'version_cli' ATTR_VERSION_CLI_LATEST = 'version_cli_latest' ATTR_REFRESH_TOKEN = 'refresh_token' ATTR_DOCKER_API = 'docker_api' +ATTR_FULL_ACCESS = 'full_access' +ATTR_PROTECTED = 'protected' +ATTR_RATING = 'rating' SERVICE_MQTT = 'mqtt' @@ -227,6 +230,14 @@ SECURITY_PROFILE = 'profile' SECURITY_DEFAULT = 'default' SECURITY_DISABLE = 'disable' +PRIVILEGED_NET_ADMIN = 'NET_ADMIN' +PRIVILEGED_SYS_ADMIN = 'SYS_ADMIN' +PRIVILEGED_SYS_RAWIO = 'SYS_RAWIO' +PRIVILEGED_IPC_LOCK = 'IPC_LOCK' +PRIVILEGED_SYS_TIME = 'SYS_TIME' +PRIVILEGED_SYS_NICE = 'SYS_NICE' +PRIVILEGED_SYS_RESOURCE = 'SYS_RESOURCE' + FEATURES_SHUTDOWN = 'shutdown' FEATURES_REBOOT = 'reboot' FEATURES_HASSOS = 'hassos' diff --git a/hassio/docker/addon.py b/hassio/docker/addon.py index 260a4e9ca..444c4d24a 100644 --- a/hassio/docker/addon.py +++ b/hassio/docker/addon.py @@ -67,6 +67,11 @@ class DockerAddon(DockerInterface): return 'host' return None + @property + def full_access(self): + """Return True if full access is enabled.""" + return not self.addon.protected and self.addon.with_full_access + @property def hostname(self): """Return slug/id of addon.""" @@ -223,7 +228,7 @@ class DockerAddon(DockerInterface): }) # Docker API support - if self.addon.with_docker_api: + if not self.addon.protected and self.addon.access_docker_api: volumes.update({ "/var/run/docker.sock": { 'bind': "/var/run/docker.sock", 'mode': 'ro' @@ -254,6 +259,11 @@ class DockerAddon(DockerInterface): if self._is_running(): return True + # Security check + if not self.addon.protected: + _LOGGER.warning( + "%s run with disabled proteced mode!", self.addon.name) + # cleanup self._stop() @@ -263,6 +273,7 @@ class DockerAddon(DockerInterface): hostname=self.hostname, detach=True, init=True, + privileged=self.full_access, ipc_mode=self.ipc, stdin_open=self.addon.with_stdin, network_mode=self.network_mode, diff --git a/hassio/exceptions.py b/hassio/exceptions.py index 9cd18e146..89b2207cb 100644 --- a/hassio/exceptions.py +++ b/hassio/exceptions.py @@ -76,6 +76,19 @@ class HostServiceError(HostError): class HostAppArmorError(HostError): """Host apparmor functions fails.""" + pass + + +# API + +class APIError(HassioError): + """API errors.""" + pass + + +class APINotSupportedError(HassioNotSupportedError): + """API not supported error.""" + pass # utils/gdbus