3 points par GN⁺ 2024-08-01 | 1 commentaires | Partager sur WhatsApp
  • Docker-OSX exécute macOS basé sur QEMU + KVM dans un conteneur Docker et fournit une sortie X11, SSH, VNC, l’intégration USB avec l’iPhone, la génération de numéros de série pour la recherche en sécurité sur iMessage, etc.
  • Le mode d’exécution consiste à transmettre à Docker le périphérique /dev/kvm, le socket X11, le forwarding de ports et la variable d’environnement SHORTNAME pour choisir la version de macOS ; des exemples sont inclus de Catalina 10.15 à Tahoe 16.
  • Les images sont organisées par usage, comme latest, auto, naked et naked-auto ; il est possible d’attacher une image .img créée soi-même ou d’exécuter des tâches en ligne de commande avec une image Catalina préconfigurée.
  • Les prérequis sont un hôte x86_64 compatible KVM, la virtualisation activée dans le BIOS et au moins 20 Go d’espace disque ; 50 Go sont nécessaires avec Xcode, et au moins 50 Go avec :auto.
  • Outre Linux, l’exécution est aussi possible avec la virtualisation imbriquée WSL2 de Windows 11 build 22000+, mais la sortie d’affichage doit être configurée via WSLg, VNC ou un environnement de bureau.

Exécuter macOS dans un conteneur Docker

  • Docker-OSX est un projet qui exécute macOS dans un conteneur Docker
    • Il fonctionne sur QEMU + KVM
    • Il prend en charge le forwarding X11
    • Il fournit une configuration où l’USB de l’iPhone fonctionne
    • Il indique permettre la recherche en sécurité sur macOS depuis Linux et Windows
  • Le projet est construit sur OSX-KVM et mentionne également KVM-OpenCore et OpenCorePkg
  • Une image Docker Hub est aussi fournie : sickcodes/docker-osx

Versions macOS prises en charge et lancement rapide

  • Le Quick Start consiste à passer les éléments suivants à docker run
    • --device /dev/kvm
    • -p 50922:10022 pour SSH
    • Le volume /tmp/.X11-unix pour X11
    • DISPLAY
    • SHORTNAME pour choisir la version de macOS
  • Les cibles d’exécution incluses dans le README sont les suivantes
    • High Sierra 10.13

    • Mojave 10.14

    • Catalina 10.15

    • Big Sur 11

    • Monterey 12

    • Ventura 13

    • Sonoma 14

    • Sequoia 15

      • Tahoe 16
      • Certains exemples à partir de Monterey utilisent aussi GENERATE_UNIQUE=true avec MASTER_PLIST_URL
      • Les exemples Sonoma, Sequoia et Tahoe incluent aussi CPU='Haswell-noTSX' et CPUID_FLAGS

Types d’images et usages

  • Docker-OSX fournit des images de conteneur adaptées à différents objectifs
    • sickcodes/docker-osx:latest : pour essayer rapidement ou créer soi-même une image macOS
    • sickcodes/docker-osx:auto : utilise un système Catalina préconfiguré, avec le nom d’utilisateur user et le mot de passe alpine
    • sickcodes/docker-osx:naked : exécute une image .img fournie par l’utilisateur
    • sickcodes/docker-osx:naked-auto : automatise SSH et l’exécution de commandes en passant USERNAME, PASSWORD et OSX_COMMANDS à l’image utilisateur
    • sickcodes/docker-osx:big-sur, :monterey, :ventura, :sonoma, :high-sierra, :mojave : pour exécuter une version précise
  • L’image naked est adaptée aux workflows consistant à redémarrer plusieurs fois une image disque existante ou à ramener un conteneur à un état antérieur
  • auto et naked-auto peuvent être utilisés pour des tâches centrées sur la ligne de commande ou des tâches headless, comme des builds basés sur Homebrew

Principales fonctionnalités

  • Les fonctionnalités indiquées par Docker-OSX sont les suivantes
    • Utilisation d’iPhone OSX KVM sous Linux avec usbfluxd
    • Exécution d’une VM macOS Monterey
    • Partage de dossiers
    • Passthrough USB et hotplug
    • Activation de SSH : localhost:50922
    • Activation de VNC : localhost:8888 avec la version ./vnc
    • Recherche en sécurité sur iMessage via un générateur de numéros de série
    • Forwarding X11
    • Prise en charge de Big Sur, d’images personnalisées et du mode headless Xvfb
    • Possibilité de cloner un conteneur avec docker commit
  • Kubernetes est également pris en charge ; le Helm Chart et la documentation se trouvent dans le répertoire helm

Prérequis et configuration initiale

  • Les prérequis minimaux sont les suivants
    • 20 Go ou plus d’espace disque
    • 50 Go avec Xcode
    • Au moins 50 Go avec :auto
    • Virtualisation activée dans le BIOS
    • Hôte x86_64 compatible KVM
  • La configuration initiale consiste à installer QEMU et les dépendances associées sur l’hôte, puis à activer libvirtd, virtlogd et les modules noyau KVM
  • Des commandes d’installation de paquets sont fournies pour Arch, Ubuntu/Debian et CentOS/RHEL/Fedora
  • L’utilisateur peut devoir appartenir aux groupes Docker, KVM et libvirt, et l’état d’exécution du daemon Docker doit aussi être vérifié

Conditions d’exécution sous Windows

  • L’exécution de Docker-OSX sous Windows est possible dans un environnement Windows 11 + WSL2
    • Windows 11 build 22000+, version 21H2 ou ultérieure, est requis
    • Après l’installation de WSL, ajouter nestedVirtualization=true à .wslconfig
    • Dans la distribution WSL, vérifier avec kvm-ok la disponibilité de /dev/kvm et de l’accélération KVM
    • Dans Docker for Windows, il faut activer le moteur basé sur WSL2 et l’intégration avec la distribution WSL par défaut
  • Les méthodes de sortie vidéo se répartissent en 3 options
    • WSLg : l’option la plus simple et recommandée, mais elle peut présenter des problèmes de transmission du clavier ou d’affichage d’une seconde souris
    • VNC : utiliser QEMU VNC ou la configuration de la section VNC
    • Desktop Environment : consomme davantage de ressources, mais offre une expérience complète de bureau Linux

Partage de fichiers et gestion des disques

  • sshfs est présenté comme la méthode de partage la plus simple et la plus sûre
    • Sous Linux/Windows, monter le rootfs macOS dans l’espace utilisateur sous la forme sshfs user@localhost: -p 50922 ~/mnt/osx
  • Le partage QEMU 9p est également possible
    • Transmettre le dossier hôte au conteneur sous /mnt/hostshare
    • Le monter dans macOS avec sudo -S mount_9p hostshare
  • Le partage NFS est aussi décrit
    • Enregistrer le répertoire partagé dans /etc/exports sur l’hôte
    • Démarrer le conteneur Docker-OSX avec --network host
    • Utiliser mount_nfs dans le terminal macOS
  • Lorsque l’espace disque Docker est insuffisant, /var/lib/docker peut être déplacé vers un disque externe, du stockage bloc, NFS, etc., puis remplacé par un lien symbolique
    • Il est recommandé de suivre le tutoriel correspondant uniquement si l’on accepte le risque de suppression des images et layers Docker actuels

USB iPhone et passthrough USB

  • Sur PC de bureau, une méthode de passthrough USB iPhone basée sur VFIO est indiquée via un lien séparé
  • Sur ordinateur portable, PC, etc., un passthrough USB en réseau avec usbfluxd peut être utilisé
    • Connecter un iPhone ou un iPad en USB sous Linux
    • Exposer usbmuxd sur le port TCP 5000
    • Depuis l’invité macOS, se connecter à l’hôte sous la forme usbfluxd -f -r 172.17.0.1:5000
    • Il est indiqué que l’appareil apparaît après avoir fermé puis rouvert des applications comme Xcode
  • Pour le passthrough USB classique, il est indiqué qu’il faut démarrer QEMU en tant que root
    • Vérifier le bus et le port avec lsusb -t
    • Utiliser notamment --privileged, /dev/kvm, EXTRA="-device ... usb-host ..."
    • Pendant l’exécution de la VM, le système hôte ne peut pas accéder au périphérique USB concerné

Headless, VNC, SPICE et exécution distante

  • L’exécution headless consiste à retirer deux lignes liées à X11 dans docker run
    • Suppression du volume /tmp/.X11-unix
    • Suppression de la variable d’environnement DISPLAY
  • Les conteneurs headless basés sur des images personnalisées sont présentés comme utiles pour les pipelines CI/CD
  • VNC peut être utilisé en local uniquement, mais le README précise qu’il n’y a aucun chiffrement TLS/HTTPS
    • Il indique que l’usage d’un tunnel SSH et la fermeture des ports externes rendent l’ensemble sûr
  • SPICE est également utilisable
    • Connexion avec remote-viewer spice://localhost:3001
    • L’option -disable-ticketing dans l’exemple autorise l’accès à la VM sans authentification ; il est donc recommandé de consulter le manuel SPICE pour configurer l’authentification

Numéros de série et recherche iMessage/iCloud

  • Les valeurs à modifier pour utiliser iMessage ou iCloud sont les suivantes
    • SERIAL
    • BOARD_SERIAL
    • UUID
    • MAC_ADDRESS
    • ROM est décrit comme l’adresse MAC en minuscules sans deux-points
  • Docker-OSX propose deux méthodes
    • GENERATE_UNIQUE=true : générer des valeurs uniques au runtime
    • GENERATE_SPECIFIC=true : utiliser des valeurs spécifiées
  • ./custom/generate-unique-machine-values.sh peut générer des numéros de série, des adresses MAC, des sorties CSV/TSV et une image de disque de démarrage
  • Le numéro de série peut être vérifié dans macOS avec ioreg -l | grep IOPlatformSerialNumber

Performances, résolution et configuration réseau

  • Il est indiqué que osx-optimizer peut rendre le conteneur plus rapide
    • Ignorer l’écran de connexion GUI
    • Désactiver l’indexation Spotlight
    • Désactiver l’arrière-plan lourd de l’écran de connexion
    • Désactiver les mises à jour
  • La résolution peut être modifiée avec les variables d’environnement WIDTH et HEIGHT
    • Elles doivent être utilisées avec GENERATE_UNIQUE=true ou GENERATE_SPECIFIC=true
    • Le démarrage prend environ 30 secondes de plus pour créer une nouvelle partition de boot
    • Une résolution incorrecte est configurée par défaut en 800x600
  • L’adaptateur réseau peut être modifié via une variable d’environnement
    • Connexion Internet rapide : NETWORKING=vmxnet3
    • Connexion Internet lente : NETWORKING=e1000-82545em
  • Dans une installation distante, activer le forwarding IPv4 peut améliorer les performances, mais l’adresse IP de l’hôte peut fuiter même si un VPN est utilisé dans le conteneur

Dépannage et limitations

  • Si le daemon Docker ne fonctionne pas, l’erreur docker: unknown server OS: . peut apparaître
    • sudo dockerd
    • sudo systemctl --start dockerd
    • sudo systemctl --enable --now dockerd
  • Il n’est pas possible d’allouer plus de RAM que sur la machine physique
    • La valeur par défaut est -e RAM=3
    • En cas de surallocation, l’erreur cannot set up guest memory 'pc.ram': Cannot allocate memory peut apparaître
  • Des erreurs liées à ALSA peuvent apparaître pendant l’initialisation du conteneur ou le démarrage ; si le démarrage et les fonctionnalités sont normaux, il est indiqué qu’il n’y a pas lieu de s’inquiéter
  • Les éléments suivants restent dans la TODO
    • Documentation pour les chercheurs en sécurité
    • Accélération GPU
    • Prise en charge de virt-manager

Licence et avis

  • Docker-OSX est sous licence GPL v3+
  • Il est précisé que l’utilisation de Docker-OSX comme outil pour créer des logiciels propriétaires est autorisée
  • Le projet inclut des avis relatifs à la recherche en sécurité Apple et à l’Apple Bug Bounty Program, et renvoie vers un article séparé sur les questions juridiques liées à Hackintosh, OSX-KVM et Docker-OSX
  • Les noms de produits, logos, marques et marques déposées mentionnés dans le projet sont la propriété de leurs détenteurs respectifs, lesquels ne sont pas affiliés au dépôt et ne le sponsorisent ni ne le garantissent

1 commentaires

 
GN⁺ 2024-08-01
Avis sur Hacker News
  • C’est important pour les personnes qui voudraient réellement utiliser le projet, mais je ne comprends pas pourquoi autant de recettes de build de type Dockerfile téléchargent des ressources arbitraires depuis Internet pendant le processus de build.
    Le Dockerfile de ce projet récupère lui aussi 2 dépôts Git et 1 script au moment du build.
    Non seulement cela échoue sur des serveurs de build sandboxés sans accès à Internet, mais toute personne un tant soit peu soucieuse de sécurité doit auditer l’intégralité de la recette de build avant de l’utiliser.
    Il ne suffit plus de vérifier uniquement les dépendances indiquées dans les spécifications de build comme README, requirements.txt ou package.json ; au vu des récentes pannes d’infrastructures critiques et de la hausse des attaques sur la chaîne d’approvisionnement, c’est une évolution très préoccupante.

    • Je déteste vraiment quand un projet va chercher des fichiers de build sur Internet. En général, cela arrive de manière inattendue, et au-delà des problèmes de sécurité, cela rend beaucoup plus difficile le packaging des logiciels qui en dépendent.
      On se retrouve avec de mauvaises surprises : problèmes de version, absence d’Internet, ou pire, dépendance qui n’est plus disponible. Les distributions autonomes devraient être la norme.
    • La réponse, c’est le churn. Le domaine DevOps change tellement vite que plus personne n’a le temps de comprendre quelle est la « bonne façon » de faire.
    • La bonne direction consiste à attendre que les grands acteurs open source comme Red Hat, SUSE ou Canonical sécurisent les builds.
      Fedora et openSUSE ont généralement des politiques imposant que les paquets de la distribution, y compris les images de conteneurs, soient construits uniquement à partir des paquets du dépôt, ou n’utilisent que des binaires explicitement ajoutés pendant le build.
      Donc si l’on peut l’installer avec dnf/zypper install ou le récupérer depuis le registre de conteneurs du fournisseur, on peut faire confiance à l’artefact.
      Si l’on a besoin du tout dernier bleeding edge, il faut accepter des ressources arbitraires venues d’Internet.
      Il est difficile pour un développeur open source quelconque de produire des artefacts de build prêts pour l’offline et dignes de confiance, et il n’a pas l’infrastructure pour cela. C’est précisément pour cela que des entreprises comme Red Hat ou SUSE existent.
      Les entreprises pesant des milliards de dollars acceptent volontiers de payer quelqu’un pour faire la plomberie : transformer des artefacts arbitraires d’Internet en artefacts fiables, reproductibles et signés, suivre les CVE et fournir des mises à jour régulières.
    • Je ne vois pas en quoi c’est différent du fait que JavaScript tire des dizaines de milliers de dépendances juste pour afficher une page web.
      Dans les années 80, on imaginait des composants logiciels réutilisables et modulaires, qu’on emboîterait comme des briques Lego ; à l’époque, on appelait ça CASE. Maintenant, c’est en quelque sorte réalisé, mais évidemment cela a un coût.
    • La raison principale est probablement de garder l’organisation de la configuration dans un dépôt Git séparé.
      Si le Dockerfile ne fait pas de clone, il faut des instructions de pré-build du type « utilisez --recursive lors du clone, ou git submodule init pour récupérer l’autre dépôt dans le répertoire de travail courant ».
  • La seule possibilité d’accélération GPU consiste à passer une dGPU prise en charge via PCI passthrough. Les AMD RX 6xxx et plus récentes peuvent fonctionner avec macOS 14.x, mais les Nvidia modernes n’ont aucune chance.
    Les iGPU Intel fonctionnent jusqu’à Comet Lake, et certains Ice Lake, mais rien de plus récent.
    Les builds macOS pour Apple Silicon semblent difficiles à émuler pour un bon moment, même s’il existe quelques travaux initiaux sur le boot d’ARM Darwin.
    De plus, AMD n’a pas Intel VT-x, donc la virtualisation est cassée sur les hôtes AMD, mais avec un hack étrange basé sur une ancienne version de VirtualBox, on peut faire fonctionner Docker dans une certaine mesure via émulation.

    • En théorie, quelqu’un pourrait créer un pilote d’affichage pour l’accélération 3D libvirt/kvm/qemu comme il en existe sous Windows et Linux. Cela permettrait alors d’utiliser les performances GPU sur presque tous les GPU, même si les performances ne seraient pas optimales.
      AMD dispose de sa propre alternative à VT-x, AMD-V, donc cela devrait fonctionner sans problème. En revanche, faire démarrer macOS sur un CPU AMD pose d’autres difficultés, généralement contournées via le chargement de kext ou d’autres astuces.
      Je ne vois pas bien l’intérêt de faire tourner un système d’exploitation complet dans Docker. Autant le distribuer en OVA ou dans le format de virtualisation que l’on préfère. Un qcow2 et un script bash pour démarrer la VM suffiraient sans doute.
    • La partie « AMD n’a pas Intel VT-x, donc la virtualisation est cassée sur les hôtes AMD », ça ne se fait pas avec AMD-V ?
  • Articles liés :
    Docker-OSX: Run macOS VM in a Docker - https://news.ycombinator.com/item?id=34374710 - janvier 2023, 110 commentaires
    macOS in QEMU in Docker - https://news.ycombinator.com/item?id=23419101 - juin 2020, 186 commentaires

  • Je l’ai configuré il y a quelques mois à titre d’expérience, et ça fonctionnait plutôt bien. Mais j’ai découvert que pour qu’iMessage fonctionne, l’application envoie un identifiant matériel à Apple, et que ce projet utilise des valeurs factices.
    À partir de là, j’ai commencé à glisser sur la pente du « ça ne va pas le faire », et j’ai appris que ces valeurs factices pouvaient être signalées par Apple, avec pour conséquence que l’identifiant iCloud soit potentiellement marqué comme spammeur et que l’accès depuis d’autres appareils soit restreint.
    La seule option consiste à essayer des valeurs en boucle avec un script de génération d’identifiants matériels vaguement lié, jusqu’à trouver une valeur qui « fonctionne », sans signal clair indiquant qu’elle est réellement correcte ni qu’elle ne nuit pas à la réputation iCloud.
    À part ça, ça fonctionnait vraiment bien, et c’est très utile en cas d’urgence.

    • La méthode consistant à « changer de HWID jusqu’à ce que ça marche » était aussi courante pour faire fonctionner iMessage sur Hackintosh. On pouvait vérifier si cela fonctionnait sur checkcoverage.apple.com.
      On s’est vite rendu compte qu’il était plus simple de copier le serial d’un vrai Mac ancien.
      Cela dit, cet outil semble plus utile pour des usages comme des scripts de build dépendant de frameworks macOS propriétaires, plutôt que comme ordinateur personnel.
    • Pour la recherche en sécurité, il vaut généralement mieux ne pas utiliser son compte iCloud principal, ni aucun autre compte principal.
  • Je veux simplement tester si l’on peut compiler pour iOS. Par exemple avec Unity, React Native, etc.
    Même si la compilation prend 5 fois plus de temps, ce pourrait être plutôt chouette du point de vue de la liberté

    • La compilation croisée est très probablement une meilleure approche : https://github.com/tpoechtrager/osxcross
      C’est aussi ainsi que Godot compile pour iOS : https://github.com/godotengine/build-containers/blob/main/Do...
      Il existe aussi une image Docker avec les outils préinstallés, mais il faut quelques ajustements pour cibler iOS : https://github.com/shepherdjerred/macos-cross-compiler
      Quand j’étais chez RStudio, aujourd’hui Posit, j’ai travaillé sur la compilation croisée C/C++/Fortran/Rust depuis un hôte Linux vers macOS x86_64/aarch64
      Si vous téléchargez depuis Posit Package Manager (https://p3m.dev/client/) un package R contenant du code natif, il a été compilé de manière croisée comme ça :)
    • Je l’ai fait moi-même. Il fallait trouver un moyen de partager le port USB à travers Docker et, d’après les instructions du dépôt, ça relevait presque de la magie noire, mais après avoir compilé l’app iOS, j’ai pu l’exécuter sur un iPhone
    • Ce serait impressionnant si, dans cet environnement sur une machine Windows, on pouvait compiler une app iOS React Native avec des modules Swift natifs et l’exécuter dans le simulateur
  • J’avais interviewé Sick Codes à propos de cette approche produit : https://www.vice.com/en/article/akdmb8/open-source-app-lets-...
    Il existe aussi OSX-PROXMOX, qui fait quelque chose de similaire sur un homeserver Proxmox : https://github.com/luchina-gabriel/OSX-PROXMOX
    Personnellement, j’utilise ce dernier sur un HP Z420 Xeon, et c’est très stable, surtout avec le passthrough GPU

  • Ce serait bien de pouvoir faire tourner la synchronisation iCloud sur un homeserver. Actuellement, il n’existe pas de bon moyen de sauvegarder physiquement iCloud sur un homeserver/NAS, et ça ne fonctionne que sous Windows/Apple

    • Ces outils peuvent aider à synchroniser ces données puis à les stocker en local ou à les sauvegarder ailleurs :
      https://github.com/steilerDev/icloud-photos-sync
      https://github.com/icloud-photos-downloader/icloud_photos_do...
    • Je travaille sur une solution avec OSX-Docker et OSXPhotos. J’en suis assez proche, mais je voulais sauvegarder toutes les informations d’iCloud, y compris les modifications de métadonnées
      Il s’avère qu’iCloud ne met pas à jour les photos originales. C’est compréhensible, mais ça n’aide pas quelqu’un qui s’attend à ce que ces modifications soient incluses dans sa sauvegarde
    • Je me demande en quoi cela aide pour ce problème. Par rapport à un rsync du dossier iCloud d’un Mac/PC connecté vers un NAS, qu’est-ce que cela permet de faire différemment ?
  • Je me demande si la redistribution d’images macOS est autorisée par la licence. Ou bien ce projet distribue-t-il ouvertement des copies piratées sur Docker Hub ?

    • Je ne suis pas sûr, mais Corellium virtualisait des instances iOS, Apple l’a poursuivi en justice, puis ils ont trouvé un accord
    • C’est manifestement illégal
  • Je me demande si le développement va s’arrêter quand arriveront des versions plus récentes de macOS sans prise en charge d’Intel
    Peut-on exécuter Docker dans ce conteneur pour faire tourner macOS dans macOS ? ;)

    • En théorie, on peut toujours lancer qemu en mode émulation complète
    • On peut simplement faire ça avec n’importe quel programme de VM pris en charge
  • Je déteste vraiment quand l’expression « passthrough USB » est utilisée pour une situation qui est, au mieux, un « proxy USB via Ethernet »
    Ce n’est pas du passthrough. Cela apporte plusieurs inconvénients qui n’existent pas dans un passthrough classique, et qui peuvent même être absents d’un passthrough avancé

    • Le passthrough USB de QEMU est un vrai passthrough USB. Les problèmes du passthrough USB viennent du contrôleur USB lui-même et de la façon dont les périphériques sont énumérés ; la seule meilleure solution consiste à faire du passthrough PCIe de tout le contrôleur USB
      Mais cette approche apporte encore d’autres problèmes. C’est ce que j’ai constaté en exploitant de grandes fermes de tests de VM avec beaucoup de matériel transmis
      Cela dit, un « proxy USB via Ethernet » reste aussi un vrai passthrough ; c’est simplement un passthrough avec plus de latence que VirtIO