├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── assets └── vas-quod.png └── src ├── cgroup.rs ├── filesystem.rs ├── main.rs ├── mount.rs ├── namespace.rs ├── network.rs ├── run.rs ├── runtime.rs └── spec.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "anyhow" 5 | version = "1.0.43" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" 8 | 9 | [[package]] 10 | name = "atty" 11 | version = "0.2.14" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 14 | dependencies = [ 15 | "hermit-abi", 16 | "libc", 17 | "winapi", 18 | ] 19 | 20 | [[package]] 21 | name = "autocfg" 22 | version = "1.0.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 25 | 26 | [[package]] 27 | name = "bitflags" 28 | version = "1.2.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 31 | 32 | [[package]] 33 | name = "byteorder" 34 | version = "1.4.3" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 37 | 38 | [[package]] 39 | name = "byteordered" 40 | version = "0.5.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "32687ee8ab498526e3ef07dfbede151650ce202dc83c53494645a24677d89b37" 43 | dependencies = [ 44 | "byteorder", 45 | ] 46 | 47 | [[package]] 48 | name = "bytes" 49 | version = "1.1.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 52 | 53 | [[package]] 54 | name = "cc" 55 | version = "1.0.66" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" 58 | 59 | [[package]] 60 | name = "cfg-if" 61 | version = "1.0.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 64 | 65 | [[package]] 66 | name = "chrono" 67 | version = "0.4.19" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 70 | dependencies = [ 71 | "libc", 72 | "num-integer", 73 | "num-traits", 74 | "serde", 75 | "time", 76 | "winapi", 77 | ] 78 | 79 | [[package]] 80 | name = "clap" 81 | version = "3.0.0-beta.2" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" 84 | dependencies = [ 85 | "atty", 86 | "bitflags", 87 | "clap_derive", 88 | "indexmap", 89 | "lazy_static", 90 | "os_str_bytes", 91 | "strsim", 92 | "termcolor", 93 | "textwrap", 94 | "unicode-width", 95 | "vec_map", 96 | ] 97 | 98 | [[package]] 99 | name = "clap_derive" 100 | version = "3.0.0-beta.2" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" 103 | dependencies = [ 104 | "heck", 105 | "proc-macro-error", 106 | "proc-macro2", 107 | "quote", 108 | "syn", 109 | ] 110 | 111 | [[package]] 112 | name = "form_urlencoded" 113 | version = "1.0.1" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 116 | dependencies = [ 117 | "matches", 118 | "percent-encoding", 119 | ] 120 | 121 | [[package]] 122 | name = "futures" 123 | version = "0.3.17" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" 126 | dependencies = [ 127 | "futures-channel", 128 | "futures-core", 129 | "futures-executor", 130 | "futures-io", 131 | "futures-sink", 132 | "futures-task", 133 | "futures-util", 134 | ] 135 | 136 | [[package]] 137 | name = "futures-channel" 138 | version = "0.3.17" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" 141 | dependencies = [ 142 | "futures-core", 143 | "futures-sink", 144 | ] 145 | 146 | [[package]] 147 | name = "futures-core" 148 | version = "0.3.17" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" 151 | 152 | [[package]] 153 | name = "futures-executor" 154 | version = "0.3.17" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" 157 | dependencies = [ 158 | "futures-core", 159 | "futures-task", 160 | "futures-util", 161 | ] 162 | 163 | [[package]] 164 | name = "futures-io" 165 | version = "0.3.17" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" 168 | 169 | [[package]] 170 | name = "futures-macro" 171 | version = "0.3.17" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" 174 | dependencies = [ 175 | "autocfg", 176 | "proc-macro-hack", 177 | "proc-macro2", 178 | "quote", 179 | "syn", 180 | ] 181 | 182 | [[package]] 183 | name = "futures-sink" 184 | version = "0.3.17" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" 187 | 188 | [[package]] 189 | name = "futures-task" 190 | version = "0.3.17" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" 193 | 194 | [[package]] 195 | name = "futures-util" 196 | version = "0.3.17" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" 199 | dependencies = [ 200 | "autocfg", 201 | "futures-channel", 202 | "futures-core", 203 | "futures-io", 204 | "futures-macro", 205 | "futures-sink", 206 | "futures-task", 207 | "memchr", 208 | "pin-project-lite", 209 | "pin-utils", 210 | "proc-macro-hack", 211 | "proc-macro-nested", 212 | "slab", 213 | ] 214 | 215 | [[package]] 216 | name = "getopts" 217 | version = "0.2.21" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" 220 | dependencies = [ 221 | "unicode-width", 222 | ] 223 | 224 | [[package]] 225 | name = "hashbrown" 226 | version = "0.9.1" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 229 | 230 | [[package]] 231 | name = "heck" 232 | version = "0.3.2" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" 235 | dependencies = [ 236 | "unicode-segmentation", 237 | ] 238 | 239 | [[package]] 240 | name = "hermit-abi" 241 | version = "0.1.18" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 244 | dependencies = [ 245 | "libc", 246 | ] 247 | 248 | [[package]] 249 | name = "idna" 250 | version = "0.2.3" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 253 | dependencies = [ 254 | "matches", 255 | "unicode-bidi", 256 | "unicode-normalization", 257 | ] 258 | 259 | [[package]] 260 | name = "indexmap" 261 | version = "1.6.2" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" 264 | dependencies = [ 265 | "autocfg", 266 | "hashbrown", 267 | ] 268 | 269 | [[package]] 270 | name = "itoa" 271 | version = "0.4.7" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 274 | 275 | [[package]] 276 | name = "lazy_static" 277 | version = "1.4.0" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 280 | 281 | [[package]] 282 | name = "libc" 283 | version = "0.2.81" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" 286 | 287 | [[package]] 288 | name = "libocispec" 289 | version = "0.1.0" 290 | source = "git+https://github.com/containers/libocispec?branch=main#9d4d71a0d8a431827298e7694eebd61472a8dc59" 291 | dependencies = [ 292 | "chrono", 293 | "serde", 294 | "serde-value", 295 | "serde_derive", 296 | "serde_json", 297 | "url", 298 | ] 299 | 300 | [[package]] 301 | name = "log" 302 | version = "0.4.14" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 305 | dependencies = [ 306 | "cfg-if", 307 | ] 308 | 309 | [[package]] 310 | name = "matches" 311 | version = "0.1.8" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 314 | 315 | [[package]] 316 | name = "memchr" 317 | version = "2.4.1" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 320 | 321 | [[package]] 322 | name = "mio" 323 | version = "0.7.7" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" 326 | dependencies = [ 327 | "libc", 328 | "log", 329 | "miow", 330 | "ntapi", 331 | "winapi", 332 | ] 333 | 334 | [[package]] 335 | name = "miow" 336 | version = "0.3.7" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 339 | dependencies = [ 340 | "winapi", 341 | ] 342 | 343 | [[package]] 344 | name = "netlink-packet-core" 345 | version = "0.2.4" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "ac48279d5062bdf175bdbcb6b58ff1d6b0ecd54b951f7a0ff4bc0550fe903ccb" 348 | dependencies = [ 349 | "anyhow", 350 | "byteorder", 351 | "libc", 352 | "netlink-packet-utils", 353 | ] 354 | 355 | [[package]] 356 | name = "netlink-packet-route" 357 | version = "0.7.1" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "4c92a86a6528fe6d0a811c48d28213ca896a2b8bf2f6cadf2ab5bb12d32ec0f1" 360 | dependencies = [ 361 | "anyhow", 362 | "bitflags", 363 | "byteorder", 364 | "libc", 365 | "netlink-packet-core", 366 | "netlink-packet-utils", 367 | ] 368 | 369 | [[package]] 370 | name = "netlink-packet-utils" 371 | version = "0.4.1" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "5fcfb6f758b66e964b2339596d94078218d96aad5b32003e8e2a1d23c27a6784" 374 | dependencies = [ 375 | "anyhow", 376 | "byteorder", 377 | "paste", 378 | "thiserror", 379 | ] 380 | 381 | [[package]] 382 | name = "netlink-proto" 383 | version = "0.7.0" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "ddd06e90449ae973fe3888c1ff85949604ef5189b4ac9a2ae39518da1e00762d" 386 | dependencies = [ 387 | "bytes", 388 | "futures", 389 | "log", 390 | "netlink-packet-core", 391 | "netlink-sys", 392 | "tokio", 393 | "tokio-util", 394 | ] 395 | 396 | [[package]] 397 | name = "netlink-sys" 398 | version = "0.7.0" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "f48ea34ea0678719815c3753155067212f853ad2d8ef4a49167bae7f7c254188" 401 | dependencies = [ 402 | "futures", 403 | "libc", 404 | "log", 405 | "tokio", 406 | ] 407 | 408 | [[package]] 409 | name = "nix" 410 | version = "0.19.1" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" 413 | dependencies = [ 414 | "bitflags", 415 | "cc", 416 | "cfg-if", 417 | "libc", 418 | ] 419 | 420 | [[package]] 421 | name = "ntapi" 422 | version = "0.3.6" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 425 | dependencies = [ 426 | "winapi", 427 | ] 428 | 429 | [[package]] 430 | name = "num-integer" 431 | version = "0.1.44" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 434 | dependencies = [ 435 | "autocfg", 436 | "num-traits", 437 | ] 438 | 439 | [[package]] 440 | name = "num-traits" 441 | version = "0.2.14" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 444 | dependencies = [ 445 | "autocfg", 446 | ] 447 | 448 | [[package]] 449 | name = "ordered-float" 450 | version = "2.2.0" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "b50b8919aecb97e5ee9aceef27e24f39c46b11831130f4a6b7b091ec5de0de12" 453 | dependencies = [ 454 | "num-traits", 455 | ] 456 | 457 | [[package]] 458 | name = "os_str_bytes" 459 | version = "2.4.0" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" 462 | 463 | [[package]] 464 | name = "paste" 465 | version = "1.0.5" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" 468 | 469 | [[package]] 470 | name = "percent-encoding" 471 | version = "2.1.0" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 474 | 475 | [[package]] 476 | name = "pin-project-lite" 477 | version = "0.2.7" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 480 | 481 | [[package]] 482 | name = "pin-utils" 483 | version = "0.1.0" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 486 | 487 | [[package]] 488 | name = "proc-macro-error" 489 | version = "1.0.4" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 492 | dependencies = [ 493 | "proc-macro-error-attr", 494 | "proc-macro2", 495 | "quote", 496 | "syn", 497 | "version_check", 498 | ] 499 | 500 | [[package]] 501 | name = "proc-macro-error-attr" 502 | version = "1.0.4" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 505 | dependencies = [ 506 | "proc-macro2", 507 | "quote", 508 | "version_check", 509 | ] 510 | 511 | [[package]] 512 | name = "proc-macro-hack" 513 | version = "0.5.19" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 516 | 517 | [[package]] 518 | name = "proc-macro-nested" 519 | version = "0.1.7" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 522 | 523 | [[package]] 524 | name = "proc-macro2" 525 | version = "1.0.26" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 528 | dependencies = [ 529 | "unicode-xid", 530 | ] 531 | 532 | [[package]] 533 | name = "quote" 534 | version = "1.0.9" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 537 | dependencies = [ 538 | "proc-macro2", 539 | ] 540 | 541 | [[package]] 542 | name = "rtnetlink" 543 | version = "0.8.0" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "279f7e9a312496b3e726e776cbd1f3102bd5ffe66503c3f44d642f7327995919" 546 | dependencies = [ 547 | "byteordered", 548 | "futures", 549 | "log", 550 | "netlink-packet-route", 551 | "netlink-proto", 552 | "nix", 553 | "thiserror", 554 | "tokio", 555 | ] 556 | 557 | [[package]] 558 | name = "ryu" 559 | version = "1.0.5" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 562 | 563 | [[package]] 564 | name = "serde" 565 | version = "1.0.126" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" 568 | dependencies = [ 569 | "serde_derive", 570 | ] 571 | 572 | [[package]] 573 | name = "serde-value" 574 | version = "0.7.0" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" 577 | dependencies = [ 578 | "ordered-float", 579 | "serde", 580 | ] 581 | 582 | [[package]] 583 | name = "serde_derive" 584 | version = "1.0.126" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" 587 | dependencies = [ 588 | "proc-macro2", 589 | "quote", 590 | "syn", 591 | ] 592 | 593 | [[package]] 594 | name = "serde_json" 595 | version = "1.0.64" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 598 | dependencies = [ 599 | "itoa", 600 | "ryu", 601 | "serde", 602 | ] 603 | 604 | [[package]] 605 | name = "simple-error" 606 | version = "0.2.2" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "634bf7bc1315698154cb1b45c1db17fcd2e5ce41f925b7b4063e971536714bf1" 609 | 610 | [[package]] 611 | name = "slab" 612 | version = "0.4.4" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" 615 | 616 | [[package]] 617 | name = "strsim" 618 | version = "0.10.0" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 621 | 622 | [[package]] 623 | name = "syn" 624 | version = "1.0.72" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" 627 | dependencies = [ 628 | "proc-macro2", 629 | "quote", 630 | "unicode-xid", 631 | ] 632 | 633 | [[package]] 634 | name = "termcolor" 635 | version = "1.1.2" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 638 | dependencies = [ 639 | "winapi-util", 640 | ] 641 | 642 | [[package]] 643 | name = "textwrap" 644 | version = "0.12.1" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" 647 | dependencies = [ 648 | "unicode-width", 649 | ] 650 | 651 | [[package]] 652 | name = "thiserror" 653 | version = "1.0.29" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" 656 | dependencies = [ 657 | "thiserror-impl", 658 | ] 659 | 660 | [[package]] 661 | name = "thiserror-impl" 662 | version = "1.0.29" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" 665 | dependencies = [ 666 | "proc-macro2", 667 | "quote", 668 | "syn", 669 | ] 670 | 671 | [[package]] 672 | name = "time" 673 | version = "0.1.44" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 676 | dependencies = [ 677 | "libc", 678 | "wasi", 679 | "winapi", 680 | ] 681 | 682 | [[package]] 683 | name = "tinyvec" 684 | version = "1.2.0" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" 687 | dependencies = [ 688 | "tinyvec_macros", 689 | ] 690 | 691 | [[package]] 692 | name = "tinyvec_macros" 693 | version = "0.1.0" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 696 | 697 | [[package]] 698 | name = "tokio" 699 | version = "1.11.0" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" 702 | dependencies = [ 703 | "autocfg", 704 | "bytes", 705 | "libc", 706 | "memchr", 707 | "mio", 708 | "pin-project-lite", 709 | "winapi", 710 | ] 711 | 712 | [[package]] 713 | name = "tokio-util" 714 | version = "0.6.8" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" 717 | dependencies = [ 718 | "bytes", 719 | "futures-core", 720 | "futures-sink", 721 | "log", 722 | "pin-project-lite", 723 | "tokio", 724 | ] 725 | 726 | [[package]] 727 | name = "unicode-bidi" 728 | version = "0.3.5" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" 731 | dependencies = [ 732 | "matches", 733 | ] 734 | 735 | [[package]] 736 | name = "unicode-normalization" 737 | version = "0.1.17" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" 740 | dependencies = [ 741 | "tinyvec", 742 | ] 743 | 744 | [[package]] 745 | name = "unicode-segmentation" 746 | version = "1.7.1" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" 749 | 750 | [[package]] 751 | name = "unicode-width" 752 | version = "0.1.8" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 755 | 756 | [[package]] 757 | name = "unicode-xid" 758 | version = "0.2.2" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 761 | 762 | [[package]] 763 | name = "url" 764 | version = "2.2.2" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 767 | dependencies = [ 768 | "form_urlencoded", 769 | "idna", 770 | "matches", 771 | "percent-encoding", 772 | "serde", 773 | ] 774 | 775 | [[package]] 776 | name = "vas-quod" 777 | version = "0.1.0" 778 | dependencies = [ 779 | "chrono", 780 | "clap", 781 | "getopts", 782 | "libocispec", 783 | "nix", 784 | "rtnetlink", 785 | "serde", 786 | "serde-value", 787 | "serde_derive", 788 | "serde_json", 789 | "simple-error", 790 | "url", 791 | ] 792 | 793 | [[package]] 794 | name = "vec_map" 795 | version = "0.8.2" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 798 | 799 | [[package]] 800 | name = "version_check" 801 | version = "0.9.3" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 804 | 805 | [[package]] 806 | name = "wasi" 807 | version = "0.10.0+wasi-snapshot-preview1" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 810 | 811 | [[package]] 812 | name = "winapi" 813 | version = "0.3.9" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 816 | dependencies = [ 817 | "winapi-i686-pc-windows-gnu", 818 | "winapi-x86_64-pc-windows-gnu", 819 | ] 820 | 821 | [[package]] 822 | name = "winapi-i686-pc-windows-gnu" 823 | version = "0.4.0" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 826 | 827 | [[package]] 828 | name = "winapi-util" 829 | version = "0.1.5" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 832 | dependencies = [ 833 | "winapi", 834 | ] 835 | 836 | [[package]] 837 | name = "winapi-x86_64-pc-windows-gnu" 838 | version = "0.4.0" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 841 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vas-quod" 3 | version = "0.1.0" 4 | authors = ["flouthoc "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [features] 10 | default = ["serde", "deps-serde"] 11 | deps-serde = ["chrono/serde", "url/serde"] 12 | 13 | [dependencies] 14 | getopts = "0.2" 15 | nix = "0.19.1" 16 | simple-error = "0.2.2" 17 | clap = "3.0.0-beta.2" 18 | chrono = "0.4.7" 19 | serde = { version = "1.0.124", features = ["derive"], optional = true } 20 | url = "2.1.0" 21 | serde-value = "0.7.0" 22 | serde_json = "1.0.64" 23 | serde_derive = "1.0.125" 24 | rtnetlink = "0.8.0" 25 | libocispec = { git = "https://github.com/containers/libocispec", branch="main"} 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, flouthoc 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vas-quod 2 | 3 | 4 | A tiny minimal container runtime written in Rust. 5 | The idea is to support a minimal isolated containers without using existing runtimes, vas-quod uses linux [syscall](https://en.wikipedia.org/wiki/System_call) to achieve isolated containers { namespaces, cgroups, chroot, unshare }. 6 | 7 | ![Image](../main/assets/vas-quod.png?raw=true) 8 | 9 | ## Usage 10 | 11 | 12 | ```bash 13 | Usage: ./vas-quod - minimal container runtime [options] 14 | Options: 15 | -r, --rootfs path Path to root file-system eg. --rootfs /home/alpinefs 16 | -c, --command command 17 | Command to be executed eg. --command `curl 18 | http://google.com` 19 | -h, --help print this help menu 20 | ``` 21 | 22 | * #### rootfs 23 | Path to root filesystem 24 | 25 | Download a sample root filesystem from https://github.com/flouthoc/vas-quod/releases/download/rootfs/rootfs.tar.gz 26 | 27 | * #### command 28 | Container entrypoint command 29 | 30 | ## Roadmap 31 | * Add Support for network bridges. 32 | * Implement `-m` or `--mount` to mount read-only files from host machine. 33 | 34 | 35 | -------------------------------------------------------------------------------- /assets/vas-quod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flouthoc/vas-quod/e79464aa4510ff9480a7e1c925604d66607ad323/assets/vas-quod.png -------------------------------------------------------------------------------- /src/cgroup.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::PathBuf; 3 | 4 | use std::process; 5 | use nix::unistd; 6 | 7 | use std::os::unix::fs::PermissionsExt; 8 | 9 | static CGROUP_PATH: &str = "/sys/fs/cgroup/pids"; 10 | 11 | // no v2 :( 12 | pub fn cgroup_init(group_name: &str) { 13 | let mut cgroups_path = PathBuf::from(CGROUP_PATH); 14 | if !cgroups_path.exists() { 15 | println!("Error: Missing Cgroups Support"); 16 | process::exit(0); 17 | } 18 | 19 | cgroups_path.push(group_name); 20 | if !cgroups_path.exists() { 21 | fs::create_dir_all(&cgroups_path).unwrap(); 22 | let mut permission = fs::metadata(&cgroups_path).unwrap().permissions(); 23 | permission.set_mode(0o777); 24 | fs::set_permissions(&cgroups_path, permission).ok(); 25 | } 26 | 27 | let pids_max = cgroups_path.join("pids.max"); 28 | let notify_on_release = cgroups_path.join("notify_on_release"); 29 | let procs = cgroups_path.join("cgroup.procs"); 30 | 31 | fs::write(pids_max, b"20").unwrap(); 32 | fs::write(notify_on_release, b"1").unwrap(); 33 | fs::write(procs,format!("{}", unistd::getpid().as_raw())).unwrap(); 34 | 35 | } 36 | 37 | #[allow(dead_code)] 38 | pub fn cgroup_deinit(group_name: &str){ 39 | let mut cgroups_path = PathBuf::from(CGROUP_PATH); 40 | if !cgroups_path.exists() { 41 | println!("Error: Missing Cgroups Support"); 42 | process::exit(0); 43 | } 44 | cgroups_path.push(group_name); 45 | fs::remove_dir(cgroups_path).expect("Failed to remove the cgroup"); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/filesystem.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::PathBuf; 3 | use nix::unistd; 4 | use nix::sys::stat; 5 | use nix::Error; 6 | 7 | static ROOT_PATH: &str = "/"; 8 | static OLD_ROOT_PATH: &str = ".oldroot"; 9 | 10 | pub fn set_root_fs(rootfs: &str){ 11 | 12 | let p_root_fs = PathBuf::from(rootfs).join(OLD_ROOT_PATH); 13 | let _rm_status = fs::remove_dir_all(&p_root_fs).map_err(|_| Error::InvalidPath); 14 | let _mkdir_status = unistd::mkdir(&p_root_fs, stat::Mode::S_IRWXU | stat::Mode::S_IRWXG | stat::Mode::S_IRWXO,); 15 | let _pivot_root_status = unistd::pivot_root(rootfs, &p_root_fs); 16 | let _chdir_status = unistd::chdir(ROOT_PATH); 17 | } 18 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate getopts; 2 | extern crate simple_error; 3 | extern crate clap; 4 | 5 | use clap::{Arg, App}; 6 | use getopts::Options; 7 | use simple_error::require_with; 8 | use std::cmp::min; 9 | use std::env; 10 | use std::error::Error; 11 | use std::process; 12 | use std::cell::RefCell; 13 | use nix::sys::wait::WaitStatus; 14 | 15 | mod runtime; 16 | mod cgroup; 17 | mod filesystem; 18 | mod mount; 19 | mod namespace; 20 | mod spec; 21 | mod run; 22 | 23 | fn print_usage(program: &str, opts: &Options) { 24 | let brief = format!("Usage: {} vas-quod [options] [-- ...]", program); 25 | print!("{}", opts.usage(&brief)); 26 | } 27 | 28 | fn main() { 29 | let args: Vec = env::args().collect(); 30 | let _program = args[0].clone(); 31 | let command_vec: Vec<&str>; 32 | let rootfs: &str; 33 | 34 | let mut app = App::new("vas-quod") 35 | .version("1.0") 36 | .about("Linux Container runtime") 37 | .arg(Arg::new("command") 38 | .short('c') 39 | .long("command") 40 | .value_name("command") 41 | .about("command to be executed eg. --command 'curl http://google.com'") 42 | .min_values(1) 43 | .takes_value(true)) 44 | .arg(Arg::new("rootfs") 45 | .short('r') 46 | .long("rootfs") 47 | .value_name("rootfs") 48 | .about("Path to root file-system eg. --rootfs /home/alpinefs") 49 | .takes_value(true)) 50 | .subcommand(App::new("spec") 51 | .about("create a new specification file") 52 | .arg(Arg::new("rootless") 53 | .long("rootless") 54 | .required(false) 55 | .takes_value(false) 56 | .about("Generate a rootless spec")) 57 | .arg(Arg::new("bundle") 58 | .short('b') 59 | .long("bundle") 60 | .takes_value(true) 61 | .about("Path to bundle"))) 62 | .subcommand(App::new("run") 63 | .about("run a container") 64 | .arg(Arg::new("bundle") 65 | .short('b') 66 | .long("bundle") 67 | .takes_value(true) 68 | .about("container bundle")) 69 | .arg(Arg::new("deatch") 70 | .short('d') 71 | .long("deatch") 72 | .takes_value(true) 73 | .about("detach from the parent")) 74 | .arg(Arg::new("pid-file") 75 | .long("pid-file") 76 | .takes_value(true) 77 | .about("where to write the PID of the container")) 78 | .arg(Arg::new("config") 79 | .long("config") 80 | .short('f') 81 | .takes_value(true) 82 | .about("override the config file name")) 83 | ); 84 | 85 | let matches = app.get_matches_mut(); 86 | if let Some(ref matches) = matches.subcommand_matches("spec") { 87 | let mut bundle: &str = ""; 88 | let mut rootless: bool = false; 89 | 90 | if let Some(bundle_v) = matches.value_of("bundle"){ 91 | bundle = bundle_v; 92 | } 93 | if matches.is_present("rootless"){ 94 | rootless = true; 95 | } 96 | 97 | spec::generate_spec(bundle, rootless); 98 | return; 99 | } 100 | if let Some(ref matches) = matches.subcommand_matches("run") { 101 | let mut bundle: &str = ""; 102 | let mut config: &str = ""; 103 | let mut detach: bool = false; 104 | let mut pid_file: &str = ""; 105 | if let Some(bundle_v) = matches.value_of("bundle"){ 106 | bundle = bundle_v; 107 | } 108 | if let Some(config_v) = matches.value_of("config"){ 109 | config = config_v; 110 | } 111 | if let Some(pid_file_v) = matches.value_of("pid-file"){ 112 | pid_file = pid_file_v; 113 | } 114 | if matches.is_present("detach"){ 115 | detach = true; 116 | } 117 | run::run(config, bundle); 118 | return; 119 | } 120 | 121 | if let Some(rootfs_v) = matches.value_of("rootfs") { 122 | rootfs = rootfs_v; 123 | }else{ 124 | app.print_long_help(); 125 | return; 126 | } 127 | 128 | if let Some(_cmd) = matches.values_of("command") { 129 | command_vec = matches.values_of("command").unwrap().collect(); 130 | } else { 131 | app.print_long_help(); 132 | return; 133 | } 134 | 135 | let c = command_vec[0]; 136 | let (command, args) = determine_command_tuple(&c, &command_vec).ok().unwrap_or_else(|| { 137 | app.print_long_help(); 138 | process::exit(7); 139 | }); 140 | 141 | let exit: Result = runtime::run_container(&rootfs, command, args); 142 | match exit { 143 | Ok(exit_result) => { 144 | match exit_result { 145 | WaitStatus::Exited(pid, code) => { 146 | println!("Exit code {0} for pid {1}", code, pid); 147 | std::process::exit(code); 148 | }, 149 | _ => panic!("Unexpected exit status: {:?}", exit_result), 150 | } 151 | }, 152 | Err(e) => { 153 | panic!("Error waiting for child process: {0}", e); 154 | } 155 | } 156 | } 157 | 158 | /// Determines based on the inputs whether we are going to invoke a shell, with 159 | /// shell interpretation, or a simple unescaped argument vector. 160 | /// Rearranges arguments as needed, but doesn't reallocate. 161 | fn determine_command_tuple<'a, T: AsRef + 'a>(shell_command: &'a T, argv: &'a [T]) -> Result<(&'a str, Vec<&'a str>), Box> { 162 | let mut vec: Vec<&str> = vec![]; 163 | 164 | // Prepend shell and command string if a command string is given. 165 | //if let Some(shell_command) = shell_command { 166 | vec.push("/bin/sh"); 167 | vec.push("-c"); 168 | //vec.push(shell_command.as_ref()); 169 | //} 170 | 171 | // The args given will be the whole command if there's no shell string; 172 | // otherwise, they'll be added to the argument vector. 173 | vec.extend(argv.iter().map(|item| item.as_ref())); 174 | 175 | // Shift off the first word as the command, erroring out if no command is 176 | // given. 177 | vec.reverse(); 178 | let command = require_with!(vec.pop(), "Empty command!"); 179 | vec.reverse(); 180 | 181 | return Ok((command, vec)); 182 | } 183 | -------------------------------------------------------------------------------- /src/mount.rs: -------------------------------------------------------------------------------- 1 | use nix::mount; 2 | 3 | static PROC: &str = "proc"; 4 | static OLD_ROOT_PATH: &str = "/.oldroot"; 5 | 6 | pub fn mount_proc(){ 7 | const NONE: Option<&'static [u8]> = None; 8 | mount::mount(Some(PROC), PROC, Some(PROC), mount::MsFlags::empty(), NONE).expect("Failed to mount the /proc"); 9 | } 10 | 11 | pub fn mount_root_fs(rootfs: &str){ 12 | let _status = mount::mount(Some(rootfs),rootfs,None::<&str>,mount::MsFlags::MS_BIND | mount::MsFlags::MS_REC,None::<&str>,); 13 | } 14 | 15 | pub fn unmount_host_root_fs(){ 16 | let _status = mount::umount2(OLD_ROOT_PATH, mount::MntFlags::MNT_DETACH); 17 | } 18 | 19 | pub fn unmount_proc(){ 20 | mount::umount("proc").unwrap(); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/namespace.rs: -------------------------------------------------------------------------------- 1 | use nix::sched; 2 | 3 | pub fn create_isolated_namespace(){ 4 | // Unshare mount, network, IPC and UTS namespace 5 | sched::unshare(sched::CloneFlags::CLONE_NEWNS | sched::CloneFlags::CLONE_NEWNET | sched::CloneFlags::CLONE_NEWUTS 6 | | sched::CloneFlags::CLONE_NEWPID | sched::CloneFlags::CLONE_NEWUTS).expect("Failed to unshare"); 7 | } 8 | -------------------------------------------------------------------------------- /src/network.rs: -------------------------------------------------------------------------------- 1 | use ipnetwork::IpNetwork; 2 | use rtnetlink::{new_connection, Error, Handle}; 3 | use std::net::IpAddr; 4 | 5 | pub struct Bridge { 6 | pub name: String, 7 | pub gateway: IpNetwork, 8 | } 9 | 10 | #[allow(dead_code)] 11 | impl Bridge { 12 | pub fn new() -> Bridge { 13 | Bridge { 14 | name: "vas-quoad-container-bridge".to_string(), 15 | ip: "172.0.0.1".parse().unwrap(), 16 | } 17 | } 18 | 19 | pub fn add_bridge(&self) -> Result<(), ()> { 20 | let (connection, handle, _) = new_connection().unwrap(); 21 | handle 22 | .link() 23 | .add() 24 | .bridge(self.name.into()) 25 | .execute() 26 | .await 27 | .map_err(|e| format!("{}", e)) 28 | } 29 | 30 | pub fn add_gateway_address() -> Result<(), Error> { 31 | let mut links = handle 32 | .link() 33 | .get() 34 | .set_name_filter(self.name.to_string()) 35 | .execute(); 36 | if let Some(link) = links.try_next().await? { 37 | handle 38 | .address() 39 | .add(link.header.index, self.ip.ip(), self.ip.prefix()) 40 | .execute() 41 | .await? 42 | } 43 | Ok(()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/run.rs: -------------------------------------------------------------------------------- 1 | extern crate libocispec; 2 | extern crate serde; 3 | extern crate serde_derive; 4 | extern crate serde_json; 5 | 6 | use std::fs; 7 | use std::path::PathBuf; 8 | use std::fs::File; 9 | use std::io::prelude::*; 10 | use std::path::Path; 11 | 12 | use nix::unistd; 13 | use nix::sys::stat; 14 | use nix::Error; 15 | 16 | use crate::runtime; 17 | use std::cell::RefCell; 18 | use nix::sys::wait::WaitStatus; 19 | 20 | // TODO: Add RunOpts and use that instead of individual args 21 | 22 | pub fn run(config: &str, bundle: &str) -> nix::Result { 23 | let mut base_config: &str = "config.json"; 24 | if !config.is_empty() { 25 | base_config = config; 26 | } 27 | 28 | let spec: libocispec::runtime::Spec = match libocispec::runtime::Spec::load(base_config) { 29 | Ok(spec) => spec, 30 | Err(e) => panic!("{}", e), 31 | }; 32 | 33 | // TODO: Implement core 34 | runtime::run_container(&spec.root.as_ref().unwrap().path, 35 | spec.process.as_ref().unwrap().args.as_ref().unwrap().clone().into_iter().nth(0).as_ref().unwrap(), 36 | [].to_vec()) 37 | } 38 | -------------------------------------------------------------------------------- /src/runtime.rs: -------------------------------------------------------------------------------- 1 | use nix::sched; 2 | use nix::sys::signal::Signal; 3 | use nix::unistd; 4 | use std::process::{Command, ExitStatus}; 5 | use nix::sys::wait::{waitpid, WaitStatus, WaitPidFlag}; 6 | 7 | use crate::cgroup; 8 | use crate::filesystem; 9 | use crate::mount; 10 | use crate::namespace; 11 | use std::cell::RefCell; 12 | 13 | static CGROUP_NAME: &str = "vasquod-container"; 14 | static HOSTNAME: &str = "vasquod"; 15 | 16 | fn set_hostname(hostname: &str){ 17 | // can also use libc here 18 | unistd::sethostname(hostname).unwrap() 19 | } 20 | 21 | struct Runner<'l> { 22 | command: &'l str, 23 | command_args: &'l [&'l str] 24 | } 25 | 26 | impl<'l> Runner<'l> { 27 | fn run(self) -> isize { 28 | let exit_status: ExitStatus = Command::new(self.command).args(self.command_args) 29 | .spawn().expect("Failed to execute container command").wait().unwrap(); 30 | match exit_status.code() { 31 | Some(code) => code as isize, 32 | None => -1 33 | } 34 | } 35 | } 36 | 37 | impl Drop for Runner<'_> { 38 | fn drop(&mut self) { 39 | mount::unmount_proc(); 40 | } 41 | } 42 | 43 | fn spawn_child<'l, 's : 'l>(hostname: &str, cgroup_name: &str, rootfs: &str, command: &'s str, command_args: &'s [&'s str]) -> isize { 44 | 45 | namespace::create_isolated_namespace(); 46 | cgroup::cgroup_init(cgroup_name); 47 | set_hostname(hostname); 48 | 49 | mount::mount_root_fs(rootfs); 50 | filesystem::set_root_fs(rootfs); 51 | mount::unmount_host_root_fs(); 52 | mount::mount_proc(); 53 | 54 | // The Drop impl for Runner is the equivalent of a try/finally 55 | // block to ensure we unmount regardless of what goes wrong 56 | let run : Runner<'l> = Runner { command, command_args }; 57 | run.run() 58 | } 59 | 60 | pub fn run_container(rootfs: &str, command: &str, command_args: Vec<&str>) -> nix::Result { 61 | 62 | let group_name = CGROUP_NAME; 63 | let hostname = HOSTNAME; 64 | const STACK_SIZE: usize = 1024 * 1024; 65 | let stack: &mut [u8; STACK_SIZE] = &mut [0; STACK_SIZE]; 66 | 67 | let cb = Box::new(|| spawn_child(hostname, group_name, rootfs, command, 68 | command_args.as_slice())); 69 | 70 | //See `man clone` 71 | let clone_flags = 72 | sched::CloneFlags::CLONE_NEWNS | sched::CloneFlags::CLONE_NEWPID | sched::CloneFlags::CLONE_NEWCGROUP | sched::CloneFlags::CLONE_NEWUTS | sched::CloneFlags::CLONE_NEWIPC | sched::CloneFlags::CLONE_NEWNET; 73 | let child_pid = sched::clone(cb, stack, clone_flags, Some(Signal::SIGCHLD as i32)) 74 | .expect("Failed to create child process"); 75 | waitpid(child_pid, None) 76 | } 77 | -------------------------------------------------------------------------------- /src/spec.rs: -------------------------------------------------------------------------------- 1 | extern crate libocispec; 2 | extern crate serde; 3 | extern crate serde_derive; 4 | extern crate serde_json; 5 | 6 | use std::fs; 7 | use std::path::PathBuf; 8 | use std::fs::File; 9 | use std::io::prelude::*; 10 | use std::path::Path; 11 | 12 | use nix::unistd; 13 | use nix::sys::stat; 14 | use nix::Error; 15 | 16 | use libocispec::runtime; 17 | 18 | static BASE_SPEC: &str = r#"{ 19 | "ociVersion": "1.0.0", 20 | "process": { 21 | "terminal": true, 22 | "user": { 23 | "uid": 0, 24 | "gid": 0 25 | }, 26 | "args": [ 27 | "sh" 28 | ], 29 | "env": [ 30 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 31 | "TERM=xterm" 32 | ], 33 | "cwd": "/", 34 | "capabilities": { 35 | "bounding": [ 36 | "CAP_AUDIT_WRITE", 37 | "CAP_KILL", 38 | "CAP_NET_BIND_SERVICE" 39 | ], 40 | "effective": [ 41 | "CAP_AUDIT_WRITE", 42 | "CAP_KILL", 43 | "CAP_NET_BIND_SERVICE" 44 | ], 45 | "inheritable": [ 46 | "CAP_AUDIT_WRITE", 47 | "CAP_KILL", 48 | "CAP_NET_BIND_SERVICE" 49 | ], 50 | "permitted": [ 51 | "CAP_AUDIT_WRITE", 52 | "CAP_KILL", 53 | "CAP_NET_BIND_SERVICE" 54 | ], 55 | "ambient": [ 56 | "CAP_AUDIT_WRITE", 57 | "CAP_KILL", 58 | "CAP_NET_BIND_SERVICE" 59 | ] 60 | }, 61 | "rlimits": [ 62 | { 63 | "type": "RLIMIT_NOFILE", 64 | "hard": 1024, 65 | "soft": 1024 66 | } 67 | ], 68 | "noNewPrivileges": true 69 | }, 70 | "root": { 71 | "path": "rootfs", 72 | "readonly": true 73 | }, 74 | "hostname": "crun", 75 | "mounts": [ 76 | { 77 | "destination": "/proc", 78 | "type": "proc", 79 | "source": "proc" 80 | }, 81 | { 82 | "destination": "/dev", 83 | "type": "tmpfs", 84 | "source": "tmpfs", 85 | "options": [ 86 | "nosuid", 87 | "strictatime", 88 | "mode=755", 89 | "size=65536k" 90 | ] 91 | }, 92 | { 93 | "destination": "/dev/pts", 94 | "type": "devpts", 95 | "source": "devpts", 96 | "options": [ 97 | "nosuid", 98 | "noexec", 99 | "newinstance", 100 | "ptmxmode=0666", 101 | "mode=0620", 102 | "gid=5" 103 | ] 104 | }, 105 | { 106 | "destination": "/dev/shm", 107 | "type": "tmpfs", 108 | "source": "shm", 109 | "options": [ 110 | "nosuid", 111 | "noexec", 112 | "nodev", 113 | "mode=1777", 114 | "size=65536k" 115 | ] 116 | }, 117 | { 118 | "destination": "/dev/mqueue", 119 | "type": "mqueue", 120 | "source": "mqueue", 121 | "options": [ 122 | "nosuid", 123 | "noexec", 124 | "nodev" 125 | ] 126 | }, 127 | { 128 | "destination": "/sys", 129 | "type": "sysfs", 130 | "source": "sysfs", 131 | "options": [ 132 | "nosuid", 133 | "noexec", 134 | "nodev", 135 | "ro" 136 | ] 137 | }, 138 | { 139 | "destination": "/sys/fs/cgroup", 140 | "type": "cgroup", 141 | "source": "cgroup", 142 | "options": [ 143 | "nosuid", 144 | "noexec", 145 | "nodev", 146 | "relatime", 147 | "ro" 148 | ] 149 | } 150 | ], 151 | "linux": { 152 | "resources": { 153 | "devices": [ 154 | { 155 | "allow": false, 156 | "access": "rwm" 157 | } 158 | ] 159 | }, 160 | "namespaces": [ 161 | { 162 | "type": "pid" 163 | }, 164 | { 165 | "type": "network" 166 | }, 167 | { 168 | "type": "ipc" 169 | }, 170 | { 171 | "type": "uts" 172 | }, 173 | { 174 | "type": "mount" 175 | } 176 | ], 177 | "maskedPaths": [ 178 | "/proc/acpi", 179 | "/proc/asound", 180 | "/proc/kcore", 181 | "/proc/keys", 182 | "/proc/latency_stats", 183 | "/proc/timer_list", 184 | "/proc/timer_stats", 185 | "/proc/sched_debug", 186 | "/sys/firmware", 187 | "/proc/scsi" 188 | ], 189 | "readonlyPaths": [ 190 | "/proc/bus", 191 | "/proc/fs", 192 | "/proc/irq", 193 | "/proc/sys", 194 | "/proc/sysrq-trigger" 195 | ] 196 | } 197 | }"#; 198 | 199 | static BASE_SPEC_ROOTLESS: &str = r#"{ 200 | "ociVersion": "1.0.0", 201 | "process": { 202 | "terminal": true, 203 | "user": { 204 | "uid": 0, 205 | "gid": 0 206 | }, 207 | "args": [ 208 | "sh" 209 | ], 210 | "env": [ 211 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 212 | "TERM=xterm" 213 | ], 214 | "cwd": "/", 215 | "capabilities": { 216 | "bounding": [ 217 | "CAP_AUDIT_WRITE", 218 | "CAP_KILL", 219 | "CAP_NET_BIND_SERVICE" 220 | ], 221 | "effective": [ 222 | "CAP_AUDIT_WRITE", 223 | "CAP_KILL", 224 | "CAP_NET_BIND_SERVICE" 225 | ], 226 | "inheritable": [ 227 | "CAP_AUDIT_WRITE", 228 | "CAP_KILL", 229 | "CAP_NET_BIND_SERVICE" 230 | ], 231 | "permitted": [ 232 | "CAP_AUDIT_WRITE", 233 | "CAP_KILL", 234 | "CAP_NET_BIND_SERVICE" 235 | ], 236 | "ambient": [ 237 | "CAP_AUDIT_WRITE", 238 | "CAP_KILL", 239 | "CAP_NET_BIND_SERVICE" 240 | ] 241 | }, 242 | "rlimits": [ 243 | { 244 | "type": "RLIMIT_NOFILE", 245 | "hard": 1024, 246 | "soft": 1024 247 | } 248 | ], 249 | "noNewPrivileges": true 250 | }, 251 | "root": { 252 | "path": "rootfs", 253 | "readonly": true 254 | }, 255 | "hostname": "crun", 256 | "mounts": [ 257 | { 258 | "destination": "/proc", 259 | "type": "proc", 260 | "source": "proc" 261 | }, 262 | { 263 | "destination": "/dev", 264 | "type": "tmpfs", 265 | "source": "tmpfs", 266 | "options": [ 267 | "nosuid", 268 | "strictatime", 269 | "mode=755", 270 | "size=65536k" 271 | ] 272 | }, 273 | { 274 | "destination": "/dev/pts", 275 | "type": "devpts", 276 | "source": "devpts", 277 | "options": [ 278 | "nosuid", 279 | "noexec", 280 | "newinstance", 281 | "ptmxmode=0666", 282 | "mode=0620" 283 | ] 284 | }, 285 | { 286 | "destination": "/dev/shm", 287 | "type": "tmpfs", 288 | "source": "shm", 289 | "options": [ 290 | "nosuid", 291 | "noexec", 292 | "nodev", 293 | "mode=1777", 294 | "size=65536k" 295 | ] 296 | }, 297 | { 298 | "destination": "/dev/mqueue", 299 | "type": "mqueue", 300 | "source": "mqueue", 301 | "options": [ 302 | "nosuid", 303 | "noexec", 304 | "nodev" 305 | ] 306 | }, 307 | { 308 | "destination": "/sys", 309 | "type": "sysfs", 310 | "source": "sysfs", 311 | "options": [ 312 | "nosuid", 313 | "noexec", 314 | "nodev", 315 | "ro" 316 | ] 317 | }, 318 | { 319 | "destination": "/sys/fs/cgroup", 320 | "type": "cgroup", 321 | "source": "cgroup", 322 | "options": [ 323 | "nosuid", 324 | "noexec", 325 | "nodev", 326 | "relatime", 327 | "ro" 328 | ] 329 | } 330 | ], 331 | "linux": { 332 | "resources": { 333 | "devices": [ 334 | { 335 | "allow": false, 336 | "access": "rwm" 337 | } 338 | ] 339 | }, 340 | "namespaces": [ 341 | { 342 | "type": "pid" 343 | }, 344 | { 345 | "type": "network" 346 | }, 347 | { 348 | "type": "ipc" 349 | }, 350 | { 351 | "type": "uts" 352 | }, 353 | { 354 | "type": "user" 355 | }, 356 | { 357 | "type": "mount" 358 | } 359 | ], 360 | "maskedPaths": [ 361 | "/proc/acpi", 362 | "/proc/asound", 363 | "/proc/kcore", 364 | "/proc/keys", 365 | "/proc/latency_stats", 366 | "/proc/timer_list", 367 | "/proc/timer_stats", 368 | "/proc/sched_debug", 369 | "/sys/firmware", 370 | "/proc/scsi" 371 | ], 372 | "readonlyPaths": [ 373 | "/proc/bus", 374 | "/proc/fs", 375 | "/proc/irq", 376 | "/proc/sys", 377 | "/proc/sysrq-trigger" 378 | ] 379 | } 380 | } 381 | "#; 382 | 383 | pub fn generate_spec(bundle: &str, rootless: bool){ 384 | 385 | let config_file = Path::new("config.json"); 386 | let display = config_file.display(); 387 | let mut spec_obj: runtime::Spec; 388 | 389 | // Change base dir if --bundle or -b is specified 390 | if(!bundle.is_empty()){ 391 | let ret = match unistd::chdir(Path::new(bundle)) { 392 | Err(err) => panic!("Error: while changing to bundle path {}", err), 393 | Ok(success) => success, 394 | }; 395 | } 396 | 397 | // Generate rootless spec if --rootless is set 398 | if(rootless){ 399 | spec_obj = serde_json::from_str(&BASE_SPEC_ROOTLESS).unwrap(); 400 | }else{ 401 | spec_obj = serde_json::from_str(&BASE_SPEC).unwrap(); 402 | } 403 | 404 | 405 | match runtime::Spec::save(&spec_obj, "config.json") { 406 | Ok(_) => {}, 407 | Err(e) => panic!("Error: Unable to write spec {}", e) 408 | } 409 | 410 | } 411 | 412 | --------------------------------------------------------------------------------