{"id":18791767,"url":"https://github.com/phip1611/linux-libc-auxv","last_synced_at":"2025-04-13T14:24:06.956Z","repository":{"id":62442284,"uuid":"432513244","full_name":"phip1611/linux-libc-auxv","owner":"phip1611","description":"Linux passes an initial stack layout to applications, that contains `argc`, `argv`, `envp`, and the `auxiliary vector` right above the stack pointer. The libc of a Linux program parses this structure in its `_start`-symbol (\"crt0\") and passes the right pointers as arguments to `main` afterward. This crate helps to construct and parse this data structure in `no_std` environments and for different address spaces.","archived":false,"fork":false,"pushed_at":"2022-05-02T19:38:48.000Z","size":63,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-27T05:24:58.743Z","etag":null,"topics":["auxiliary-vector","crt0","libc","linux"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phip1611.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-27T16:38:23.000Z","updated_at":"2024-12-23T19:36:45.000Z","dependencies_parsed_at":"2022-11-01T22:02:10.935Z","dependency_job_id":null,"html_url":"https://github.com/phip1611/linux-libc-auxv","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phip1611%2Flinux-libc-auxv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phip1611%2Flinux-libc-auxv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phip1611%2Flinux-libc-auxv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phip1611%2Flinux-libc-auxv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phip1611","download_url":"https://codeload.github.com/phip1611/linux-libc-auxv/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248725775,"owners_count":21151784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auxiliary-vector","crt0","libc","linux"],"created_at":"2024-11-07T21:16:49.777Z","updated_at":"2025-04-13T14:24:06.913Z","avatar_url":"https://github.com/phip1611.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# linux-libc-auxv: Build and Parse the Initial Linux Stack Layout for Different Address Spaces\n\nLinux passes an initial stack layout to applications, that contains `argc`, `argv`, `envp`, and the `auxiliary vector`\nright above the stack pointer. The libc of a Linux program parses this structure in its `_start`-symbol (\"crt0\") and\npasses the right pointers as arguments to `main` afterwards. This crate helps to construct and parse this data structure\nin `no_std` environments and for different address spaces.\n\n**Keywords**: crt0, stack layout, AT values, AT pairs, auxvec, auxiliary vector\n\nThis crate has been tested successfully by myself in a custom runtime system for a Microkernel, that is able to load\nand start unmodified Linux binaries. The Linux binary (the libc) could find all arguments,\nenvironment variables, and the data from the auxiliary vector and print it to stdout.\n\n## How does this differ from \u003chttps://crates.io/crates/crt0stack\u003e and \u003chttps://crates.io/crates/auxv\u003e?\nThis crate supports `no_std`-contexts plus allows construction the data structure for a different address\nspace, i.e. the address space of a user application.\n\nWhen I started creating this crate, I only knew about the latter. It doesn't support `no_std`. Because\nthe first one supports `no_std` but not different address spaces, I still had to create this one.\nThe typical use case for me is to create the data structure for a different address space, like Linux does.\n\nLast but not least, my crate supports more/all of Linux's AT variables.\n\n## Functionality\n✅ build data structure for current address space \\\n✅ build data structure for **different address space** \\\n✅ parse data structure for current address space + output referenced data/pointers \\\n✅ parse data structure for **different address space** + prevent memory error / no dereferencing of pointers\n\n\n## Limitations\n\n### 32 vs 64 bit\nThe auxiliary vector contains pairs of type `(usize, usize)`. Hence, each entry takes 8 bytes on 32-bit systems\nand 16 byte on 64-bit systems. Currently, this crate produces the auxiliary vector for the architecture it is\ncompiled with. If necessary, create an issue or a PR and this will be a runtime setting. I never tested it\non a 32-bit system, but I am confident it will work.\n\n### Auxiliary Vector vs Stack Layout\nRight now, this crate can only build and serialize the whole initial stack layout but not the auxiliary vector\nstandalone.\n\n## Code Example\nThere are multiple code examples in the repository!\n`cargo run --example linux_parse_print_layout` shows you a\nreal world example.\n\n### Minimal: Build + Parse\n```rust\nuse linux_libc_auxv::{AuxVar, InitialLinuxLibcStackLayout, InitialLinuxLibcStackLayoutBuilder};\n\n/// Minimal example that builds the initial linux libc stack layout and parses it again.\nfn main() {\n    let builder = InitialLinuxLibcStackLayoutBuilder::new()\n        // can contain terminating zero; not mandatory in the builder\n        .add_arg_v(\"./first_arg\\0\")\n        .add_arg_v(\"./second_arg\")\n        .add_env_v(\"FOO=BAR\\0\")\n        .add_env_v(\"PATH=/bin\")\n        .add_aux_v(AuxVar::Clktck(100))\n        .add_aux_v(AuxVar::Random([\n            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n        ]))\n        .add_aux_v(AuxVar::ExecFn(\"/usr/bin/foo\"))\n        .add_aux_v(AuxVar::Platform(\"x86_64\"));\n\n    // memory where we serialize the data structure into\n    let mut buf = vec![0; builder.total_size()];\n\n    // assume user stack is at 0x7fff0000\n    let user_base_addr = 0x7fff0000;\n    unsafe {\n        builder.serialize_into_buf(buf.as_mut_slice(), user_base_addr);\n    }\n\n    // So far, this is memory safe, as long as the slice is valid memory. No pointers are\n    // dereferenced yet.\n    let parsed = InitialLinuxLibcStackLayout::from(buf.as_slice());\n\n    println!(\"There are {} arguments.\", parsed.argc());\n    println!(\n        \"There are {} environment variables.\",\n        parsed.envv_ptr_iter().count()\n    );\n    println!(\n        \"There are {} auxiliary vector entries/AT variables.\",\n        parsed.aux_serialized_iter().count()\n    );\n\n    println!(\"  argv\");\n    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr\n    for (i, arg) in parsed.argv_ptr_iter().enumerate() {\n        println!(\"    [{}] @ {:?}\", i, arg);\n    }\n\n    println!(\"  envp\");\n    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr\n    for (i, env) in parsed.envv_ptr_iter().enumerate() {\n        println!(\"    [{}] @ {:?}\", i, env);\n    }\n\n    println!(\"  aux\");\n    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr\n    for aux in parsed.aux_serialized_iter() {\n        if aux.key().value_in_data_area() {\n            println!(\"    {:?} =\u003e @ {:?}\", aux.key(), aux.val() as *const u8);\n        } else {\n            println!(\"    {:?} =\u003e {:?}\", aux.key(), aux.val() as *const u8);\n        }\n    }\n}\n```\n\n### Code Example Output\n```text\nThere are 2 arguments.\nThere are 2 environment variables.\nThere are 5 auxiliary vector entries/AT variables.\n  argv\n    [0] @ 0x7fff00b0\n    [1] @ 0x7fff00bc\n  envp\n    [0] @ 0x7fff00c9\n    [1] @ 0x7fff00d1\n  aux\n    Platform =\u003e @ 0x7fff0090\n    Clktck =\u003e 0x64\n    Random =\u003e @ 0x7fff0097\n    ExecFn =\u003e @ 0x7fff00db\n    Null =\u003e 0x0\n```\n\n## Terminology (in Code)\nThe whole data structure is called `InitialLinuxLibcStackLayout` by me. There is no official name. It contains\nthe arguments (`argc` and `argv`), the environment variables (`envp` or `envv`), and the auxiliary vector\n(`AT-variables`, `auxv`, `aux-pairs`, `aux entries`).\n\nThe `argv`-array will reference data in the `argv data area`, the `envv`-array will reference data in the\n`envv data area`, and some of the `auxv`-values might reference data in the `auxv data area`.\n\nSometimes (in some articles), the auxiliary vector even describes the whole data structure.\n\n## Layout of the Data Structure\n```text\nnull                                   [HIGH ADDRESS]\nfilename (c string)\n\u003cenv data area\u003e\n\u003cargs data area\u003e\n// round up to 16 byte\n\u003caux vec data area\u003e\n// round up to 16 byte alignment\nAT_VAR_3 = \u003cpoints to aux vec data area\u003e\nAT_VAR_2 = integer\nAT_VAR_1 = integer\n// round up to 16 byte alignment\nenvv[2] = null\nenvv[1] = \u003cpoints to env data area\u003e\nenvv[0] = \u003cpoints to env data area\u003e\nargv[2] = null\nargv[1] = \u003cpoints to args data area\u003e\nargv[0] = \u003cpoints to args data area\u003e\nargc = integer \u003clibc entry stack top\u003e  [LOW ADDRESS]\n```\n\n## MSRV\n1.56.1 stable / Rust edition 2021\n\n## Background Information \u0026 Links\n- \u003chttps://lwn.net/Articles/631631/\u003e (good overview with ASCII graphics)\n- \u003chttps://lwn.net/Articles/519085/\u003e\n- \u003chttps://elixir.bootlin.com/linux/v5.15.5/source/fs/binfmt_elf.c#L257\u003e (code in Linux that constructs `auxv`)\n- \u003chttps://man7.org/linux/man-pages/man3/getauxval.3.html\u003e\n- \u003chttps://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_zSeries/x895.html\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphip1611%2Flinux-libc-auxv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphip1611%2Flinux-libc-auxv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphip1611%2Flinux-libc-auxv/lists"}