virtualization.scm 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017 Ryan Moe <ryan.moe@gmail.com>
  3. ;;; Copyright © 2018, 2020 Ludovic Courtès <ludo@gnu.org>
  4. ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  8. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  9. ;;; under the terms of the GNU General Public License as published by
  10. ;;; the Free Software Foundation; either version 3 of the License, or (at
  11. ;;; your option) any later version.
  12. ;;;
  13. ;;; GNU Guix is distributed in the hope that it will be useful, but
  14. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;;; GNU General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU General Public License
  19. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  20. (define-module (gnu services virtualization)
  21. #:use-module (gnu bootloader)
  22. #:use-module (gnu bootloader grub)
  23. #:use-module (gnu image)
  24. #:use-module (gnu packages admin)
  25. #:use-module (gnu packages gdb)
  26. #:use-module (gnu packages package-management)
  27. #:use-module (gnu packages ssh)
  28. #:use-module (gnu packages virtualization)
  29. #:use-module (gnu services base)
  30. #:use-module (gnu services configuration)
  31. #:use-module (gnu services dbus)
  32. #:use-module (gnu services shepherd)
  33. #:use-module (gnu services ssh)
  34. #:use-module (gnu services)
  35. #:use-module (gnu system file-systems)
  36. #:use-module (gnu system hurd)
  37. #:use-module (gnu system image)
  38. #:use-module (gnu system images hurd)
  39. #:use-module (gnu system shadow)
  40. #:use-module (gnu system)
  41. #:use-module (guix derivations)
  42. #:use-module (guix gexp)
  43. #:use-module (guix modules)
  44. #:use-module (guix monads)
  45. #:use-module (guix packages)
  46. #:use-module (guix records)
  47. #:use-module (guix store)
  48. #:use-module (guix utils)
  49. #:use-module (srfi srfi-9)
  50. #:use-module (srfi srfi-26)
  51. #:use-module (rnrs bytevectors)
  52. #:use-module (ice-9 match)
  53. #:export (%hurd-vm-operating-system
  54. hurd-vm-configuration
  55. hurd-vm-configuration?
  56. hurd-vm-configuration-os
  57. hurd-vm-configuration-qemu
  58. hurd-vm-configuration-image
  59. hurd-vm-configuration-disk-size
  60. hurd-vm-configuration-memory-size
  61. hurd-vm-configuration-options
  62. hurd-vm-configuration-id
  63. hurd-vm-configuration-net-options
  64. hurd-vm-configuration-secrets
  65. hurd-vm-disk-image
  66. hurd-vm-port
  67. hurd-vm-net-options
  68. hurd-vm-service-type
  69. libvirt-configuration
  70. libvirt-service-type
  71. virtlog-configuration
  72. virtlog-service-type
  73. %qemu-platforms
  74. lookup-qemu-platforms
  75. qemu-platform?
  76. qemu-platform-name
  77. qemu-binfmt-configuration
  78. qemu-binfmt-configuration?
  79. qemu-binfmt-service-type))
  80. (define (uglify-field-name field-name)
  81. (let ((str (symbol->string field-name)))
  82. (string-join
  83. (string-split (string-delete #\? str) #\-)
  84. "_")))
  85. (define (quote-val val)
  86. (string-append "\"" val "\""))
  87. (define (serialize-field field-name val)
  88. (format #t "~a = ~a\n" (uglify-field-name field-name) val))
  89. (define (serialize-string field-name val)
  90. (serialize-field field-name (quote-val val)))
  91. (define (serialize-boolean field-name val)
  92. (serialize-field field-name (if val 1 0)))
  93. (define (serialize-integer field-name val)
  94. (serialize-field field-name val))
  95. (define (build-opt-list val)
  96. (string-append
  97. "["
  98. (string-join (map quote-val val) ",")
  99. "]"))
  100. (define optional-list? list?)
  101. (define optional-string? string?)
  102. (define (serialize-list field-name val)
  103. (serialize-field field-name (build-opt-list val)))
  104. (define (serialize-optional-list field-name val)
  105. (if (null? val)
  106. (format #t "# ~a = []\n" (uglify-field-name field-name))
  107. (serialize-list field-name val)))
  108. (define (serialize-optional-string field-name val)
  109. (if (string-null? val)
  110. (format #t "# ~a = \"\"\n" (uglify-field-name field-name))
  111. (serialize-string field-name val)))
  112. (define-configuration libvirt-configuration
  113. (libvirt
  114. (package libvirt)
  115. "Libvirt package.")
  116. (listen-tls?
  117. (boolean #t)
  118. "Flag listening for secure TLS connections on the public TCP/IP port.
  119. must set @code{listen} for this to have any effect.
  120. It is necessary to setup a CA and issue server certificates before
  121. using this capability.")
  122. (listen-tcp?
  123. (boolean #f)
  124. "Listen for unencrypted TCP connections on the public TCP/IP port.
  125. must set @code{listen} for this to have any effect.
  126. Using the TCP socket requires SASL authentication by default. Only
  127. SASL mechanisms which support data encryption are allowed. This is
  128. DIGEST_MD5 and GSSAPI (Kerberos5)")
  129. (tls-port
  130. (string "16514")
  131. "Port for accepting secure TLS connections This can be a port number,
  132. or service name")
  133. (tcp-port
  134. (string "16509")
  135. "Port for accepting insecure TCP connections This can be a port number,
  136. or service name")
  137. (listen-addr
  138. (string "0.0.0.0")
  139. "IP address or hostname used for client connections.")
  140. (mdns-adv?
  141. (boolean #f)
  142. "Flag toggling mDNS advertisement of the libvirt service.
  143. Alternatively can disable for all services on a host by
  144. stopping the Avahi daemon.")
  145. (mdns-name
  146. (string (string-append "Virtualization Host " (gethostname)))
  147. "Default mDNS advertisement name. This must be unique on the
  148. immediate broadcast network.")
  149. (unix-sock-group
  150. (string "root")
  151. "UNIX domain socket group ownership. This can be used to
  152. allow a 'trusted' set of users access to management capabilities
  153. without becoming root.")
  154. (unix-sock-ro-perms
  155. (string "0777")
  156. "UNIX socket permissions for the R/O socket. This is used
  157. for monitoring VM status only.")
  158. (unix-sock-rw-perms
  159. (string "0770")
  160. "UNIX socket permissions for the R/W socket. Default allows
  161. only root. If PolicyKit is enabled on the socket, the default
  162. will change to allow everyone (eg, 0777)")
  163. (unix-sock-admin-perms
  164. (string "0777")
  165. "UNIX socket permissions for the admin socket. Default allows
  166. only owner (root), do not change it unless you are sure to whom
  167. you are exposing the access to.")
  168. (unix-sock-dir
  169. (string "/var/run/libvirt")
  170. "The directory in which sockets will be found/created.")
  171. (auth-unix-ro
  172. (string "polkit")
  173. "Authentication scheme for UNIX read-only sockets. By default
  174. socket permissions allow anyone to connect")
  175. (auth-unix-rw
  176. (string "polkit")
  177. "Authentication scheme for UNIX read-write sockets. By default
  178. socket permissions only allow root. If PolicyKit support was compiled
  179. into libvirt, the default will be to use 'polkit' auth.")
  180. (auth-tcp
  181. (string "sasl")
  182. "Authentication scheme for TCP sockets. If you don't enable SASL,
  183. then all TCP traffic is cleartext. Don't do this outside of a dev/test
  184. scenario.")
  185. (auth-tls
  186. (string "none")
  187. "Authentication scheme for TLS sockets. TLS sockets already have
  188. encryption provided by the TLS layer, and limited authentication is
  189. done by certificates.
  190. It is possible to make use of any SASL authentication mechanism as
  191. well, by using 'sasl' for this option")
  192. (access-drivers
  193. (optional-list '())
  194. "API access control scheme.
  195. By default an authenticated user is allowed access to all APIs. Access
  196. drivers can place restrictions on this.")
  197. (key-file
  198. (string "")
  199. "Server key file path. If set to an empty string, then no private key
  200. is loaded.")
  201. (cert-file
  202. (string "")
  203. "Server key file path. If set to an empty string, then no certificate
  204. is loaded.")
  205. (ca-file
  206. (string "")
  207. "Server key file path. If set to an empty string, then no CA certificate
  208. is loaded.")
  209. (crl-file
  210. (string "")
  211. "Certificate revocation list path. If set to an empty string, then no
  212. CRL is loaded.")
  213. (tls-no-sanity-cert
  214. (boolean #f)
  215. "Disable verification of our own server certificates.
  216. When libvirtd starts it performs some sanity checks against its own
  217. certificates.")
  218. (tls-no-verify-cert
  219. (boolean #f)
  220. "Disable verification of client certificates.
  221. Client certificate verification is the primary authentication mechanism.
  222. Any client which does not present a certificate signed by the CA
  223. will be rejected.")
  224. (tls-allowed-dn-list
  225. (optional-list '())
  226. "Whitelist of allowed x509 Distinguished Name.")
  227. (sasl-allowed-usernames
  228. (optional-list '())
  229. "Whitelist of allowed SASL usernames. The format for username
  230. depends on the SASL authentication mechanism.")
  231. (tls-priority
  232. (string "NORMAL")
  233. "Override the compile time default TLS priority string. The
  234. default is usually \"NORMAL\" unless overridden at build time.
  235. Only set this is it is desired for libvirt to deviate from
  236. the global default settings.")
  237. (max-clients
  238. (integer 5000)
  239. "Maximum number of concurrent client connections to allow
  240. over all sockets combined.")
  241. (max-queued-clients
  242. (integer 1000)
  243. "Maximum length of queue of connections waiting to be
  244. accepted by the daemon. Note, that some protocols supporting
  245. retransmission may obey this so that a later reattempt at
  246. connection succeeds.")
  247. (max-anonymous-clients
  248. (integer 20)
  249. "Maximum length of queue of accepted but not yet authenticated
  250. clients. Set this to zero to turn this feature off")
  251. (min-workers
  252. (integer 5)
  253. "Number of workers to start up initially.")
  254. (max-workers
  255. (integer 20)
  256. "Maximum number of worker threads.
  257. If the number of active clients exceeds @code{min-workers},
  258. then more threads are spawned, up to max_workers limit.
  259. Typically you'd want max_workers to equal maximum number
  260. of clients allowed.")
  261. (prio-workers
  262. (integer 5)
  263. "Number of priority workers. If all workers from above
  264. pool are stuck, some calls marked as high priority
  265. (notably domainDestroy) can be executed in this pool.")
  266. (max-requests
  267. (integer 20)
  268. "Total global limit on concurrent RPC calls.")
  269. (max-client-requests
  270. (integer 5)
  271. "Limit on concurrent requests from a single client
  272. connection. To avoid one client monopolizing the server
  273. this should be a small fraction of the global max_requests
  274. and max_workers parameter.")
  275. (admin-min-workers
  276. (integer 1)
  277. "Same as @code{min-workers} but for the admin interface.")
  278. (admin-max-workers
  279. (integer 5)
  280. "Same as @code{max-workers} but for the admin interface.")
  281. (admin-max-clients
  282. (integer 5)
  283. "Same as @code{max-clients} but for the admin interface.")
  284. (admin-max-queued-clients
  285. (integer 5)
  286. "Same as @code{max-queued-clients} but for the admin interface.")
  287. (admin-max-client-requests
  288. (integer 5)
  289. "Same as @code{max-client-requests} but for the admin interface.")
  290. (log-level
  291. (integer 3)
  292. "Logging level. 4 errors, 3 warnings, 2 information, 1 debug.")
  293. (log-filters
  294. (string "3:remote 4:event")
  295. "Logging filters.
  296. A filter allows selecting a different logging level for a given category
  297. of logs
  298. The format for a filter is one of:
  299. @itemize
  300. @item x:name
  301. @item x:+name
  302. @end itemize
  303. where @code{name} is a string which is matched against the category
  304. given in the @code{VIR_LOG_INIT()} at the top of each libvirt source
  305. file, e.g., \"remote\", \"qemu\", or \"util.json\" (the name in the
  306. filter can be a substring of the full category name, in order
  307. to match multiple similar categories), the optional \"+\" prefix
  308. tells libvirt to log stack trace for each message matching
  309. name, and @code{x} is the minimal level where matching messages should
  310. be logged:
  311. @itemize
  312. @item 1: DEBUG
  313. @item 2: INFO
  314. @item 3: WARNING
  315. @item 4: ERROR
  316. @end itemize
  317. Multiple filters can be defined in a single filters statement, they just
  318. need to be separated by spaces.")
  319. (log-outputs
  320. (string "3:syslog:libvirtd")
  321. "Logging outputs.
  322. An output is one of the places to save logging information
  323. The format for an output can be:
  324. @table @code
  325. @item x:stderr
  326. output goes to stderr
  327. @item x:syslog:name
  328. use syslog for the output and use the given name as the ident
  329. @item x:file:file_path
  330. output to a file, with the given filepath
  331. @item x:journald
  332. output to journald logging system
  333. @end table
  334. In all case the x prefix is the minimal level, acting as a filter
  335. @itemize
  336. @item 1: DEBUG
  337. @item 2: INFO
  338. @item 3: WARNING
  339. @item 4: ERROR
  340. @end itemize
  341. Multiple outputs can be defined, they just need to be separated by spaces.")
  342. (audit-level
  343. (integer 1)
  344. "Allows usage of the auditing subsystem to be altered
  345. @itemize
  346. @item 0: disable all auditing
  347. @item 1: enable auditing, only if enabled on host
  348. @item 2: enable auditing, and exit if disabled on host.
  349. @end itemize
  350. ")
  351. (audit-logging
  352. (boolean #f)
  353. "Send audit messages via libvirt logging infrastructure.")
  354. (host-uuid
  355. (optional-string "")
  356. "Host UUID. UUID must not have all digits be the same.")
  357. (host-uuid-source
  358. (string "smbios")
  359. "Source to read host UUID.
  360. @itemize
  361. @item @code{smbios}: fetch the UUID from @code{dmidecode -s system-uuid}
  362. @item @code{machine-id}: fetch the UUID from @code{/etc/machine-id}
  363. @end itemize
  364. If @code{dmidecode} does not provide a valid UUID a temporary UUID
  365. will be generated.")
  366. (keepalive-interval
  367. (integer 5)
  368. "A keepalive message is sent to a client after
  369. @code{keepalive_interval} seconds of inactivity to check if
  370. the client is still responding. If set to -1, libvirtd will
  371. never send keepalive requests; however clients can still send
  372. them and the daemon will send responses.")
  373. (keepalive-count
  374. (integer 5)
  375. "Maximum number of keepalive messages that are allowed to be sent
  376. to the client without getting any response before the connection is
  377. considered broken.
  378. In other words, the connection is automatically
  379. closed approximately after
  380. @code{keepalive_interval * (keepalive_count + 1)} seconds since the last
  381. message received from the client. When @code{keepalive-count} is
  382. set to 0, connections will be automatically closed after
  383. @code{keepalive-interval} seconds of inactivity without sending any
  384. keepalive messages.")
  385. (admin-keepalive-interval
  386. (integer 5)
  387. "Same as above but for admin interface.")
  388. (admin-keepalive-count
  389. (integer 5)
  390. "Same as above but for admin interface.")
  391. (ovs-timeout
  392. (integer 5)
  393. "Timeout for Open vSwitch calls.
  394. The @code{ovs-vsctl} utility is used for the configuration and
  395. its timeout option is set by default to 5 seconds to avoid
  396. potential infinite waits blocking libvirt."))
  397. (define* (libvirt-conf-file config)
  398. "Return a libvirtd config file."
  399. (plain-file "libvirtd.conf"
  400. (with-output-to-string
  401. (lambda ()
  402. (serialize-configuration config libvirt-configuration-fields)))))
  403. (define %libvirt-accounts
  404. (list (user-group (name "libvirt") (system? #t))))
  405. (define (%libvirt-activation config)
  406. (let ((sock-dir (libvirt-configuration-unix-sock-dir config)))
  407. #~(begin
  408. (use-modules (guix build utils))
  409. (mkdir-p #$sock-dir))))
  410. (define (libvirt-shepherd-service config)
  411. (let* ((config-file (libvirt-conf-file config))
  412. (libvirt (libvirt-configuration-libvirt config)))
  413. (list (shepherd-service
  414. (documentation "Run the libvirt daemon.")
  415. (provision '(libvirtd))
  416. (start #~(make-forkexec-constructor
  417. (list (string-append #$libvirt "/sbin/libvirtd")
  418. "-f" #$config-file)
  419. ;; For finding qemu and ip binaries.
  420. #:environment-variables
  421. (list (string-append
  422. "PATH=/run/current-system/profile/bin:"
  423. "/run/current-system/profile/sbin"))))
  424. (stop #~(make-kill-destructor))))))
  425. (define libvirt-service-type
  426. (service-type (name 'libvirt)
  427. (extensions
  428. (list
  429. (service-extension polkit-service-type
  430. (compose list libvirt-configuration-libvirt))
  431. (service-extension profile-service-type
  432. (lambda (config)
  433. (list
  434. (libvirt-configuration-libvirt config)
  435. qemu)))
  436. (service-extension activation-service-type
  437. %libvirt-activation)
  438. (service-extension shepherd-root-service-type
  439. libvirt-shepherd-service)
  440. (service-extension account-service-type
  441. (const %libvirt-accounts))))
  442. (default-value (libvirt-configuration))))
  443. (define-record-type* <virtlog-configuration>
  444. virtlog-configuration make-virtlog-configuration
  445. virtlog-configuration?
  446. (libvirt virtlog-configuration-libvirt
  447. (default libvirt))
  448. (log-level virtlog-configuration-log-level
  449. (default 3))
  450. (log-filters virtlog-configuration-log-filters
  451. (default "3:remote 4:event"))
  452. (log-outputs virtlog-configuration-log-outputs
  453. (default "3:syslog:virtlogd"))
  454. (max-clients virtlog-configuration-max-clients
  455. (default 1024))
  456. (max-size virtlog-configuration-max-size
  457. (default 2097152)) ;; 2MB
  458. (max-backups virtlog-configuration-max-backups
  459. (default 3)))
  460. (define* (virtlogd-conf-file config)
  461. "Return a virtlogd config file."
  462. (plain-file "virtlogd.conf"
  463. (string-append
  464. "log_level = " (number->string (virtlog-configuration-log-level config)) "\n"
  465. "log_filters = \"" (virtlog-configuration-log-filters config) "\"\n"
  466. "log_outputs = \"" (virtlog-configuration-log-outputs config) "\"\n"
  467. "max_clients = " (number->string (virtlog-configuration-max-clients config)) "\n"
  468. "max_size = " (number->string (virtlog-configuration-max-size config)) "\n"
  469. "max_backups = " (number->string (virtlog-configuration-max-backups config)) "\n")))
  470. (define (virtlogd-shepherd-service config)
  471. (let* ((config-file (virtlogd-conf-file config))
  472. (libvirt (virtlog-configuration-libvirt config)))
  473. (list (shepherd-service
  474. (documentation "Run the virtlog daemon.")
  475. (provision '(virtlogd))
  476. (start #~(make-forkexec-constructor
  477. (list (string-append #$libvirt "/sbin/virtlogd")
  478. "-f" #$config-file)))
  479. (stop #~(make-kill-destructor))))))
  480. (define virtlog-service-type
  481. (service-type (name 'virtlogd)
  482. (extensions
  483. (list
  484. (service-extension shepherd-root-service-type
  485. virtlogd-shepherd-service)))
  486. (default-value (virtlog-configuration))))
  487. (define (generate-libvirt-documentation)
  488. (generate-documentation
  489. `((libvirt-configuration ,libvirt-configuration-fields))
  490. 'libvirt-configuration))
  491. ;;;
  492. ;;; Transparent QEMU emulation via binfmt_misc.
  493. ;;;
  494. ;; Platforms that QEMU can emulate.
  495. (define-record-type <qemu-platform>
  496. (qemu-platform name family magic mask)
  497. qemu-platform?
  498. (name qemu-platform-name) ;string
  499. (family qemu-platform-family) ;string
  500. (magic qemu-platform-magic) ;bytevector
  501. (mask qemu-platform-mask)) ;bytevector
  502. (define-syntax bv
  503. (lambda (s)
  504. "Expand the given string into a bytevector."
  505. (syntax-case s ()
  506. ((_ str)
  507. (string? (syntax->datum #'str))
  508. (let ((bv (u8-list->bytevector
  509. (map char->integer
  510. (string->list (syntax->datum #'str))))))
  511. bv)))))
  512. ;;; The platform descriptions below are taken from
  513. ;;; 'scripts/qemu-binfmt-conf.sh' in QEMU.
  514. (define %i386
  515. (qemu-platform "i386" "i386"
  516. (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00")
  517. (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  518. (define %i486
  519. (qemu-platform "i486" "i386"
  520. (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00")
  521. (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  522. (define %alpha
  523. (qemu-platform "alpha" "alpha"
  524. (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90")
  525. (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  526. (define %arm
  527. (qemu-platform "arm" "arm"
  528. (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00")
  529. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  530. (define %armeb
  531. (qemu-platform "armeb" "arm"
  532. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28")
  533. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  534. (define %sparc
  535. (qemu-platform "sparc" "sparc"
  536. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02")
  537. (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  538. (define %sparc32plus
  539. (qemu-platform "sparc32plus" "sparc"
  540. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12")
  541. (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  542. (define %ppc
  543. (qemu-platform "ppc" "ppc"
  544. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14")
  545. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  546. (define %ppc64
  547. (qemu-platform "ppc64" "ppc"
  548. (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15")
  549. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  550. (define %ppc64le
  551. (qemu-platform "ppc64le" "ppcle"
  552. (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00")
  553. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00")))
  554. (define %m68k
  555. (qemu-platform "m68k" "m68k"
  556. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04")
  557. (bv "\xff\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  558. ;; XXX: We could use the other endianness on a MIPS host.
  559. (define %mips
  560. (qemu-platform "mips" "mips"
  561. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
  562. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  563. (define %mipsel
  564. (qemu-platform "mipsel" "mips"
  565. (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
  566. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  567. (define %mipsn32
  568. (qemu-platform "mipsn32" "mips"
  569. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
  570. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  571. (define %mipsn32el
  572. (qemu-platform "mipsn32el" "mips"
  573. (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
  574. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  575. (define %mips64
  576. (qemu-platform "mips64" "mips"
  577. (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
  578. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  579. (define %mips64el
  580. (qemu-platform "mips64el" "mips"
  581. (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
  582. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  583. (define %riscv32
  584. (qemu-platform "riscv32" "riscv"
  585. (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00")
  586. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  587. (define %riscv64
  588. (qemu-platform "riscv64" "riscv"
  589. (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00")
  590. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  591. (define %sh4
  592. (qemu-platform "sh4" "sh4"
  593. (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00")
  594. (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  595. (define %sh4eb
  596. (qemu-platform "sh4eb" "sh4"
  597. (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a")
  598. (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  599. (define %s390x
  600. (qemu-platform "s390x" "s390x"
  601. (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16")
  602. (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  603. (define %aarch64
  604. (qemu-platform "aarch64" "arm"
  605. (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00")
  606. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
  607. (define %hppa
  608. (qemu-platform "hppa" "hppa"
  609. (bv "\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f")
  610. (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
  611. (define %qemu-platforms
  612. (list %i386 %i486 %alpha %arm %sparc32plus %ppc %ppc64 %ppc64le %m68k
  613. %mips %mipsel %mipsn32 %mipsn32el %mips64 %mips64el
  614. %riscv32 %riscv64 %sh4 %sh4eb %s390x %aarch64 %hppa))
  615. (define (lookup-qemu-platforms . names)
  616. "Return the list of QEMU platforms that match NAMES--a list of names such as
  617. \"arm\", \"hppa\", etc."
  618. (filter (lambda (platform)
  619. (member (qemu-platform-name platform) names))
  620. %qemu-platforms))
  621. (define-record-type* <qemu-binfmt-configuration>
  622. qemu-binfmt-configuration make-qemu-binfmt-configuration
  623. qemu-binfmt-configuration?
  624. (qemu qemu-binfmt-configuration-qemu
  625. (default qemu))
  626. (platforms qemu-binfmt-configuration-platforms
  627. (default '())) ;safest default
  628. (guix-support? qemu-binfmt-configuration-guix-support?
  629. (default #f)))
  630. (define (qemu-platform->binfmt qemu platform)
  631. "Return a gexp that evaluates to a binfmt string for PLATFORM, using the
  632. given QEMU package."
  633. (define (bytevector->binfmt-string bv)
  634. ;; Return a binfmt-friendly string representing BV. Hex-encode every
  635. ;; character, in particular because the doc notes "that you must escape
  636. ;; any NUL bytes; parsing halts at the first one".
  637. (string-concatenate
  638. (map (lambda (n)
  639. (string-append "\\x"
  640. (string-pad (number->string n 16) 2 #\0)))
  641. (bytevector->u8-list bv))))
  642. (match platform
  643. (($ <qemu-platform> name family magic mask)
  644. ;; See 'Documentation/binfmt_misc.txt' in the kernel.
  645. #~(string-append ":qemu-" #$name ":M::"
  646. #$(bytevector->binfmt-string magic)
  647. ":" #$(bytevector->binfmt-string mask)
  648. ":" #$(file-append qemu "/bin/qemu-" name)
  649. ":" ;FLAGS go here
  650. ))))
  651. (define %binfmt-mount-point
  652. (file-system-mount-point %binary-format-file-system))
  653. (define %binfmt-register-file
  654. (string-append %binfmt-mount-point "/register"))
  655. (define qemu-binfmt-shepherd-services
  656. (match-lambda
  657. (($ <qemu-binfmt-configuration> qemu platforms)
  658. (list (shepherd-service
  659. (provision '(qemu-binfmt))
  660. (documentation "Install binfmt_misc handlers for QEMU.")
  661. (requirement '(file-system-/proc/sys/fs/binfmt_misc))
  662. (start #~(lambda ()
  663. ;; Register the handlers for all of PLATFORMS.
  664. (for-each (lambda (str)
  665. (call-with-output-file
  666. #$%binfmt-register-file
  667. (lambda (port)
  668. (display str port))))
  669. (list
  670. #$@(map (cut qemu-platform->binfmt qemu
  671. <>)
  672. platforms)))
  673. #t))
  674. (stop #~(lambda (_)
  675. ;; Unregister the handlers.
  676. (for-each (lambda (name)
  677. (let ((file (string-append
  678. #$%binfmt-mount-point
  679. "/qemu-" name)))
  680. (call-with-output-file file
  681. (lambda (port)
  682. (display "-1" port)))))
  683. '#$(map qemu-platform-name platforms))
  684. #f)))))))
  685. (define qemu-binfmt-guix-chroot
  686. (match-lambda
  687. ;; Add QEMU and its dependencies to the guix-daemon chroot so that our
  688. ;; binfmt_misc handlers work in the chroot (otherwise 'execve' would fail
  689. ;; with ENOENT.)
  690. ;;
  691. ;; The 'F' flag of binfmt_misc is meant to address this problem by loading
  692. ;; the interpreter upfront rather than lazily, but apparently that is
  693. ;; insufficient (perhaps it loads the 'qemu-ARCH' binary upfront but looks
  694. ;; up its dependencies lazily?).
  695. (($ <qemu-binfmt-configuration> qemu platforms guix?)
  696. (if guix? (list qemu) '()))))
  697. (define qemu-binfmt-service-type
  698. ;; TODO: Make a separate binfmt_misc service out of this?
  699. (service-type (name 'qemu-binfmt)
  700. (extensions
  701. (list (service-extension file-system-service-type
  702. (const
  703. (list %binary-format-file-system)))
  704. (service-extension shepherd-root-service-type
  705. qemu-binfmt-shepherd-services)
  706. (service-extension guix-service-type
  707. qemu-binfmt-guix-chroot)))
  708. (default-value (qemu-binfmt-configuration))
  709. (description
  710. "This service supports transparent emulation of binaries
  711. compiled for other architectures using QEMU and the @code{binfmt_misc}
  712. functionality of the kernel Linux.")))
  713. ;;;
  714. ;;; Secrets for guest VMs.
  715. ;;;
  716. (define (secret-service-activation port)
  717. "Return an activation snippet that fetches sensitive material at local PORT,
  718. over TCP. Reboot upon failure."
  719. (with-imported-modules '((gnu build secret-service)
  720. (guix build utils))
  721. #~(begin
  722. (use-modules (gnu build secret-service))
  723. (let ((sent (secret-service-receive-secrets #$port)))
  724. (unless sent
  725. (sleep 3)
  726. (reboot))))))
  727. (define secret-service-type
  728. (service-type
  729. (name 'secret-service)
  730. (extensions (list (service-extension activation-service-type
  731. secret-service-activation)))
  732. (description
  733. "This service fetches secret key and other sensitive material over TCP at
  734. boot time. This service is meant to be used by virtual machines (VMs) that
  735. can only be accessed by their host.")))
  736. (define (secret-service-operating-system os)
  737. "Return an operating system based on OS that includes the secret-service,
  738. that will be listening to receive secret keys on port 1004, TCP."
  739. (operating-system
  740. (inherit os)
  741. ;; Arrange so that the secret service activation snippet shows up before
  742. ;; the OpenSSH and Guix activation snippets. That way, we receive OpenSSH
  743. ;; and Guix keys before the activation snippets try to generate fresh keys
  744. ;; for nothing.
  745. (services (append (operating-system-user-services os)
  746. (list (service secret-service-type 1004))))))
  747. ;;;
  748. ;;; The Hurd in VM service: a Childhurd.
  749. ;;;
  750. (define %hurd-vm-operating-system
  751. (operating-system
  752. (inherit %hurd-default-operating-system)
  753. (host-name "childhurd")
  754. (timezone "Europe/Amsterdam")
  755. (bootloader (bootloader-configuration
  756. (bootloader grub-minimal-bootloader)
  757. (target "/dev/vda")
  758. (timeout 0)))
  759. (packages (cons* gdb-minimal
  760. (operating-system-packages
  761. %hurd-default-operating-system)))
  762. (services (cons*
  763. (service openssh-service-type
  764. (openssh-configuration
  765. (openssh openssh-sans-x)
  766. (use-pam? #f)
  767. (port-number 2222)
  768. (permit-root-login #t)
  769. (allow-empty-passwords? #t)
  770. (password-authentication? #t)))
  771. %base-services/hurd))))
  772. (define-record-type* <hurd-vm-configuration>
  773. hurd-vm-configuration make-hurd-vm-configuration
  774. hurd-vm-configuration?
  775. (os hurd-vm-configuration-os ;<operating-system>
  776. (default %hurd-vm-operating-system))
  777. (qemu hurd-vm-configuration-qemu ;<package>
  778. (default qemu-minimal))
  779. (image hurd-vm-configuration-image ;string
  780. (thunked)
  781. (default (hurd-vm-disk-image this-record)))
  782. (disk-size hurd-vm-configuration-disk-size ;number or 'guess
  783. (default 'guess))
  784. (memory-size hurd-vm-configuration-memory-size ;number
  785. (default 512))
  786. (options hurd-vm-configuration-options ;list of string
  787. (default `("--snapshot")))
  788. (id hurd-vm-configuration-id ;#f or integer [1..]
  789. (default #f))
  790. (net-options hurd-vm-configuration-net-options ;list of string
  791. (thunked)
  792. (default (hurd-vm-net-options this-record)))
  793. (secret-root hurd-vm-configuration-secret-root ;string
  794. (default "/etc/childhurd")))
  795. (define (hurd-vm-disk-image config)
  796. "Return a disk-image for the Hurd according to CONFIG. The secret-service
  797. is added to the OS specified in CONFIG."
  798. (let ((os (secret-service-operating-system (hurd-vm-configuration-os config)))
  799. (disk-size (hurd-vm-configuration-disk-size config)))
  800. (system-image
  801. (image
  802. (inherit hurd-disk-image)
  803. (format 'compressed-qcow2)
  804. (size disk-size)
  805. (operating-system os)))))
  806. (define (hurd-vm-port config base)
  807. "Return the forwarded vm port for this childhurd config."
  808. (let ((id (or (hurd-vm-configuration-id config) 0)))
  809. (+ base (* 1000 id))))
  810. (define %hurd-vm-secrets-port 11004)
  811. (define %hurd-vm-ssh-port 10022)
  812. (define %hurd-vm-vnc-port 15900)
  813. (define (hurd-vm-net-options config)
  814. `("--device" "rtl8139,netdev=net0"
  815. "--netdev"
  816. ,(string-append "user,id=net0"
  817. ",hostfwd=tcp:127.0.0.1:"
  818. (number->string (hurd-vm-port config %hurd-vm-secrets-port))
  819. "-:1004"
  820. ",hostfwd=tcp:127.0.0.1:"
  821. (number->string (hurd-vm-port config %hurd-vm-ssh-port))
  822. "-:2222"
  823. ",hostfwd=tcp:127.0.0.1:"
  824. (number->string (hurd-vm-port config %hurd-vm-vnc-port))
  825. "-:5900")))
  826. (define (hurd-vm-shepherd-service config)
  827. "Return a <shepherd-service> for a Hurd in a Virtual Machine with CONFIG."
  828. (let ((image (hurd-vm-configuration-image config))
  829. (qemu (hurd-vm-configuration-qemu config))
  830. (memory-size (hurd-vm-configuration-memory-size config))
  831. (options (hurd-vm-configuration-options config))
  832. (id (hurd-vm-configuration-id config))
  833. (net-options (hurd-vm-configuration-net-options config))
  834. (provisions '(hurd-vm childhurd)))
  835. (define vm-command
  836. #~(append (list #$(file-append qemu "/bin/qemu-system-i386")
  837. "-m" (number->string #$memory-size)
  838. #$@net-options
  839. #$@options
  840. "--hda" #+image
  841. ;; Cause the service to be respawned if the guest
  842. ;; reboots (it can reboot for instance if it did not
  843. ;; receive valid secrets, or if it crashed.)
  844. "--no-reboot")
  845. (if (file-exists? "/dev/kvm")
  846. '("--enable-kvm")
  847. '())))
  848. (list
  849. (shepherd-service
  850. (documentation "Run the Hurd in a Virtual Machine: a Childhurd.")
  851. (provision (if id
  852. (map
  853. (cute symbol-append <>
  854. (string->symbol (number->string id)))
  855. provisions)
  856. provisions))
  857. (requirement '(loopback networking user-processes))
  858. (start
  859. (with-imported-modules
  860. (source-module-closure '((gnu build secret-service)
  861. (guix build utils)))
  862. #~(lambda ()
  863. (let ((pid (fork+exec-command #$vm-command
  864. #:user "childhurd"
  865. ;; XXX TODO: use "childhurd" after
  866. ;; updating Shepherd
  867. #:group "kvm"
  868. #:environment-variables
  869. ;; QEMU tries to write to /var/tmp
  870. ;; by default.
  871. '("TMPDIR=/tmp")))
  872. (port #$(hurd-vm-port config %hurd-vm-secrets-port))
  873. (root #$(hurd-vm-configuration-secret-root config)))
  874. (catch #t
  875. (lambda _
  876. ;; XXX: 'secret-service-send-secrets' won't complete until
  877. ;; the guest has booted and its secret service server is
  878. ;; running, which could take 20+ seconds during which PID 1
  879. ;; is stuck waiting.
  880. (if (secret-service-send-secrets port root)
  881. pid
  882. (begin
  883. (kill (- pid) SIGTERM)
  884. #f)))
  885. (lambda (key . args)
  886. (kill (- pid) SIGTERM)
  887. (apply throw key args)))))))
  888. (modules `((gnu build secret-service)
  889. (guix build utils)
  890. ,@%default-modules))
  891. (stop #~(make-kill-destructor))))))
  892. (define %hurd-vm-accounts
  893. (list (user-group (name "childhurd") (system? #t))
  894. (user-account
  895. (name "childhurd")
  896. (group "childhurd")
  897. (supplementary-groups '("kvm"))
  898. (comment "Privilege separation user for the childhurd")
  899. (home-directory "/var/empty")
  900. (shell (file-append shadow "/sbin/nologin"))
  901. (system? #t))))
  902. (define (initialize-hurd-vm-substitutes)
  903. "Initialize the Hurd VM's key pair and ACL and store it on the host."
  904. (define run
  905. (with-imported-modules '((guix build utils))
  906. #~(begin
  907. (use-modules (guix build utils)
  908. (ice-9 match))
  909. (define host-key
  910. "/etc/guix/signing-key.pub")
  911. (define host-acl
  912. "/etc/guix/acl")
  913. (match (command-line)
  914. ((_ guest-config-directory)
  915. (setenv "GUIX_CONFIGURATION_DIRECTORY"
  916. guest-config-directory)
  917. (invoke #+(file-append guix "/bin/guix") "archive"
  918. "--generate-key")
  919. (when (file-exists? host-acl)
  920. ;; Copy the host ACL.
  921. (copy-file host-acl
  922. (string-append guest-config-directory
  923. "/acl")))
  924. (when (file-exists? host-key)
  925. ;; Add the host key to the childhurd's ACL.
  926. (let ((key (open-fdes host-key O_RDONLY)))
  927. (close-fdes 0)
  928. (dup2 key 0)
  929. (execl #+(file-append guix "/bin/guix")
  930. "guix" "archive" "--authorize"))))))))
  931. (program-file "initialize-hurd-vm-substitutes" run))
  932. (define (hurd-vm-activation config)
  933. "Return a gexp to activate the Hurd VM according to CONFIG."
  934. (with-imported-modules '((guix build utils))
  935. #~(begin
  936. (use-modules (guix build utils))
  937. (define secret-directory
  938. #$(hurd-vm-configuration-secret-root config))
  939. (define ssh-directory
  940. (string-append secret-directory "/etc/ssh"))
  941. (define guix-directory
  942. (string-append secret-directory "/etc/guix"))
  943. (unless (file-exists? ssh-directory)
  944. ;; Generate SSH host keys under SSH-DIRECTORY.
  945. (mkdir-p ssh-directory)
  946. (invoke #$(file-append openssh "/bin/ssh-keygen")
  947. "-A" "-f" secret-directory))
  948. (unless (file-exists? guix-directory)
  949. (invoke #$(initialize-hurd-vm-substitutes)
  950. guix-directory)))))
  951. (define hurd-vm-service-type
  952. (service-type
  953. (name 'hurd-vm)
  954. (extensions (list (service-extension shepherd-root-service-type
  955. hurd-vm-shepherd-service)
  956. (service-extension account-service-type
  957. (const %hurd-vm-accounts))
  958. (service-extension activation-service-type
  959. hurd-vm-activation)))
  960. (default-value (hurd-vm-configuration))
  961. (description
  962. "Provide a virtual machine (VM) running GNU/Hurd, also known as a
  963. @dfn{childhurd}.")))