CroshCros Le shell Chromium OS

Ceci est la page d’accueil / documentation du crosh, le shell Chromium OS. Si vous êtes sur un appareil CrOS en ce moment, vous devriez pouvoir lancer crosh en appuyant sur Ctrl + Alt + T. Si vous n’êtes pas sur CrOS, cela ne fera probablement rien d’utile :).

Exécutez simplement help pour obtenir des informations sur les commandes disponibles et en découvrir plus.

Vous pouvez également utiliser la complétion des onglets pour trouver rapidement les commandes existantes.

C’est une aventure !

Pour les développeurs de Chromium OS

Cette section est destinée aux personnes qui piratent sur Chromium OS, en particulier lorsqu’elles ont besoin de modifier/ étendre crosh.

Avertissement de sécurité

Veuillez ne pas installer de nouveaux modules sans un examen complet de la sécurité. Tout code non sécurisé que crosh charge sera directement disponible pour les personnes en mode vérifié. C’est un vecteur d’attaque facile pour exécuter du code arbitraire et brouiller l’état de l’utilisateur. Nous ne voulons pas compromettre la sécurité du CrOS!

Si vous cherchez des évaluateurs, regardez le.Fichier /PROPRIÉTAIRES.

Où les fichiers vivent

Crosh est migré du shell vers Rust. Crosh commence à s’exécuter à partir de src/main.rs mais la plupart des commandes sont implémentées comme leur propre sous-module de l’un des modules de haut niveau (par exemple base ou dev).

Le script principal crosh contient l’implémentation héritée de la logique crosh de base tandis que d’autres fonctions héritées vivent dans les répertoires de modules. La version héritée de crosh est installée sur le périphérique en tant que crosh.sh.

Repos source

Les modules spécifiques à une carte, ou fortement spécifiques à un package, devraient généralement vivre avec cette carte et/ou ce package. Pour les fonctions qui sont toujours disponibles sur tous les périphériques CrOS, ce code doit être conservé dans ce dépôt.

Si vous n’êtes pas sûr, demandez simplement sur [email protected] .

Ajout de nouvelles commandes

Déterminez d’abord quelle stratégie d’implémentation la nouvelle commande utilisera. Lors de la sélection d’une stratégie, il est utile de savoir quelles autorisations et quels privilèges sont nécessaires. Avec la stratégie à l’esprit, consultez les différents exemples ci-dessous.

Conception de commande

Le shell crosh s’exécute dans le même environnement que le navigateur (même utilisateur/groupe, mêmes espaces de noms Linux, etc…). Ainsi, tous les outils que vous exécutez dans crosh, ou les informations que vous essayez d’acquérir, doivent être accessibles à l’utilisateur chronos.

Cependant, nous voulons rarement que crosh exécute directement les outils. Au lieu de cela, vous devez ajouter des rappels D-Bus au démon debugd et lui envoyer toutes les demandes. Nous pouvons mieux contrôler l’accès dans debugd et verrouiller les outils. Ensuite, la seule logique qui existe dans crosh est un appel IPC de bus D, puis affiche la sortie de ces programmes. La discussion sur debugd est hors de portée ici, alors consultez plutôt le répertoire debugd.

Exemples

Exemples d’implémentations :

  • Wrapper de méthode D-Bus(debugd):base::verify_ro
    Utilisez ceci lorsqu’une API D-Bus est déjà planifiée ou que crosh n’a pas les autorisations ou les capacités nécessaires.
  • Wrapper binaire externe:base::ccd_pass
    Utilisez ceci lorsqu’il existe déjà un outil de ligne de commande qui implémente la commande qui fonctionne lorsqu’elle est exécutée en tant que chronos avec les capacités de crosh.Commande
  • écrite en Rust:base::arc
    Ceci est le mieux adapté aux cas où des capacités supplémentaires ne sont pas nécessaires et qu’un outil de ligne de commande séparé n’est pas justifié.

Un exemple de workflow est inclus ci-dessous pour l’écriture d’une nouvelle commande.

Configuration du module

Choisissez un module approprié auquel la commande doit appartenir. Pour les commandes en mode dev, ce sera dev, la plupart des autres commandes appartiendront à base. Cet exemple utilisera base comme module, mais les mêmes étapes devraient toujours s’appliquer dans d’autres cas.

Choisissez ensuite un nom de commande, créez un sous-module avec ce nom et enregistrez-le avec le module parent. Pour cet exemple, la commande est verify_ro, donc le nouveau fichier source est src/base/verify_ro.rs et deux lignes doivent être ajoutées à src/base/mod.rs:

Tout d’abord, le sous-module doit être importé :

mod verify_ro;

Deuxièmement, la fonction de registre (à créer ci-dessous) doit être appelée par la fonction de registre dans le module parent src/base/mod.rs:

pub fn register(dispatcher: &mut Dispatcher) { ... verify_ro::register(dispatcher); ...}

Maintenant, le fichier source src/base/verify_ro.rs est prêt à être écrit. Commencez avec ce fichier source minimal et vérifiez que crosh compile avec cargo build:

use crate::dispatcher::Dispatcher;pub fn register(dispatcher: &mut Dispatcher) { dispatcher.register_command( Command::new( "verify_ro".to_string(), "TODO put usage here".to_string(), "TODO put description here".to_string(), ) .set_command_callback(Some(execute_verify_ro)), );}fn execute_verify_ro(_cmd: &Command, args: &Arguments) -> Result<(), dispatcher::Error> { unimplemented!();}

Implémentation de la commande

Cela suppose que les instructions ci-dessus sont déjà terminées.

Étant donné que les opérations privilégiées ne peuvent pas être exécutées par Crosh (mais doivent être implémentées dans debugd ou ailleurs), l’exemple ci-dessous se concentre sur D-Bus en particulier et suppose qu’il existe une méthode D-Bus existante qui doit être appelée à partir d’une nouvelle commande Crosh.

Notez que l’interface D-Bus de debugd a déjà des liaisons Rust générées via dev-rust/system_api, de sorte que les liaisons et la connexion D-Bus peuvent être importées avec :

use dbus::blocking::Connection;use system_api::client::OrgChromiumDebugd;

Si vous souhaitez parcourir le code source des liaisons générées, après avoir exécuté build_packages, jetez un œil au chemin suivant :

/build/${BOARD}/usr/lib/cros_rust_registry/registry/system_api-*/src/bindings/client/

Dans l’implémentation de la commande, une connexion D-Bus doit être initialisée. Une connexion de blocage est utilisée dans cet exemple.

let connection = Connection::new_system().map_err(|err| { error!("ERROR: Failed to get D-Bus connection: {}", err); dispatcher::Error::CommandReturnedError})?;

La connexion de bus peut ensuite être utilisée pour obtenir une interface vers le service souhaité, qui est dans ce cas débogué :

let conn_path = connection.with_proxy( "org.chromium.debugd", "/org/chromium/debugd", DEFAULT_DBUS_TIMEOUT,);

Le reste de l’appel de méthode utilise le fait que le trait importé system_api::client::OrgChromiumDebugd est implémenté pour system_api::client::OrgChromiumDebugd est implémenté pour system_api::client::OrgChromiumDebugdconn_path ainsi, les fonctions membres qui mappent les méthodes D-Bus peuvent être appelées à partir de conn_path. Par exemple :

conn_path .update_and_verify_fwon_usb_stop(handle) .map_err(|err| { println!("ERROR: Got unexpected result: {}", err); dispatcher::Error::CommandReturnedError })?;

Cela couvre les bases. Si vous regardez le code source réel de base::verify_ro, il fournit un exemple plus compliqué avec un appel de méthode de démarrage, un observateur et un appel de méthode d’arrêt.

Aide à la commande

Les chaînes d’aide par défaut sont remplies à l’aide du nom de la commande, de la chaîne d’utilisation, de la chaîne de description et de toutes les options ou indicateurs enregistrés via l’API du répartiteur.

Alternativement, un rappel d’aide peut être défini lors de l’enregistrement de la commande pour effectuer une logique personnalisée comme l’appel de l’option d’aide d’un binaire. Exemple:

const EXECUTABLE: &str = "/usr/bin/vmc";pub fn register(dispatcher: &mut Dispatcher) { dispatcher.register_command( Command::new("vmc".to_string(), "".to_string(), "".to_string()) .set_command_callback(Some(execute_vmc)) .set_help_callback(vmc_help), );}fn vmc_help(_cmd: &Command, w: &mut dyn Write, _level: usize) { let mut sub = process::Command::new(EXECUTABLE) .arg("--help") .stdout(Stdio::piped()) .spawn() .unwrap(); if copy(&mut sub.stdout.take().unwrap(), w).is_err() { panic!(); } if sub.wait().is_err() { panic!(); }}

Commandes obsolètes

Si vous voulez remplacer une commande crosh par une autre interface utilisateur (comme une page chrome://), et que vous voulez déprécier la commande gracieusement en laissant une note amicale si des gens essaient de l’utiliser, voici le formulaire.

# Set the vars to pass the unittests ...USAGE_storage_status=''HELP_storage_status=''# ... then unset them to hide the command from "help" output.unset USAGE_storage_status HELP_storage_statuscmd_storage_status() ( # TODO: Delete this after the R## release branch. echo "Removed. See storage_info section in chrome://system")

Assurez-vous d’ajouter le commentaire TODO afin que les gens sachent à l’avenir quand il sera POSSIBLE de le nettoyer.

Test

Développement itératif

Vous pouvez exécuter ./crosh sur votre système de bureau pour obtenir un exemple de shell. Vous pouvez tester rapidement les interactions de base (comme l’analyse d’arguments) ici, ou vérifier la sortie d’aide. Vous n’aurez pas accès aux services CrOS auxquels de nombreuses commandes crosh s’attendent à parler (via D-Bus), de sorte que ces commandes échoueront.

Si vous souhaitez charger des modules en mode dev, vous pouvez utiliser ./crosh --dev. Il ne chargera que des modules locaux (./dev.d/), donc si votre module vit ailleurs, vous pouvez le copier temporairement ici.

De même, si vous souhaitez charger des modules de périphériques amovibles, vous pouvez utiliser ./crosh --removable.

Unittests

Pour exécuter les tests unitaires, appelez cargo test --workspacedans le dossier crosh ou exécutez emege-${BOARD} crosh && FEATURES=test emerge-${BOARD}

Le coureur unittest hérité ./run_tests.sh effectue un tas de contrôles de style et de solidité de base. Exécutez-le contre toute modification du code shell!

Travaux futurs

Tout le monde devrait se sentir libre de reprendre ces idées et d’essayer de les mettre en œuvre :).

  • Déplace toutes les commandes restantes implémentées en place vers des appels de débogage afin qu’elles puissent être effectuées via D-Bus.
  • Exécutez crosh lui-même dans un bac à sable restreint (espaces de noms/seccomp/etc…). Une fois que toutes les commandes sont effectuées via IPC, il n’est pas nécessaire de conserver les fichiers privés. Cela pourrait cependant dépendre du mode de développement afin que nous ne cassions pas shell.
  • Migrez des commandes shell héritées supplémentaires vers Rust. Cela peut également être fait en même temps que la migration d’une commande vers debugd.

Documentation Crosh existante

Crosh a été initialement écrit en shell. Au moment de la rédaction, de nombreuses commandes restent encore dans shell et doivent encore être portées sur le crosh Rust. Cette documentation est conservée ici pour la maintenance de ces commandes.

API de commande

Pour chaque commande, vous définissez deux variables et une fonction. Il n’est pas nécessaire d’enregistrer les nouvelles commandes n’importe où car crosh inspectera son propre environnement d’exécution pour les découvrir.

Voici comment enregistrer une nouvelle commande foo.

# A short description of arguments that this command accepts.USAGE_foo='<some args>'HELP_foo=' Extended description of this command.'# Not required, but lets crosh detect if the foo program is available in the# current system (e.g. the package is not installed on all devices). If it# isn't available, crosh will automatically display an error message and never# call cmd_foo.EXEC_foo='/full/path/to/program'cmd_foo() ( # Implementation for the foo command. # You should validate $# and "$@" and process them first. # For invalid args, call the help function with an error message # before returning non-zero. ...foo code goes here!...)

Voir la section conception ci-dessous pour plus de détails sur quoi et comment structurer la nouvelle commande.

Aide à la commande

Si votre commande crosh appelle simplement un programme externe pour effectuer le traitement, et que ce programme offre déjà des détails d’utilisation, vous ne voulez probablement pas avoir à dupliquer les choses. Vous pouvez gérer ce scénario en définissant une fonction help_foo qui effectue l’appel respectif.

# Set the help string so crosh can discover us automatically.HELP_foo=''cmd_foo() ( ...)help_foo() ( /some/command --help)

Notez que nous avons toujours défini HELP_foo. Cela est nécessaire pour que crosh puisse nous découvrir automatiquement et nous afficher dans les listes d’utilisateurs correspondantes (comme la commande help_advanced). Nous n’avons pas besoin de définir USAGE_foo car la fonction help_foo le fait pour nous.

Masquage des commandes

Si une commande n’est pas encore prête pour le « prime time”, vous voudrez peut-être l’avoir dans crosh pour des tests précoces, mais ne pas l’afficher dans la sortie help où les utilisateurs peuvent facilement la découvrir (bien sûr, le code est entièrement public, donc toute personne lisant la source réelle peut la trouver). Voici comment vous le faites.

# Set the vars to pass the unittests ...USAGE_vmc=''HELP_vmc=''# ... then unset them to hide the command from "help" output.unset USAGE_vmc HELP_vmccmd_vmc() ( ...)

Related Posts

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *