New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a fake uname implementation to the Linux stdenv (that returns hardcoded values) #25240
Conversation
This is an implementation of the uname command that just returns constant data. It should be compatible with coreutils uname.
Makes it much easier to inspect what's included in a particular stdenv stage.
This has two purity advantages: - This makes `uname -m` return the processor architecture we're building for, not the architecture the build is running on. This mainly affects ARM, where we want to build armv6l packages on an armv7l package. The v7 processors are very capable of executing v6 code, but many build systems will look at `uname -m` and decide to do different things based on the result. Examples: - coreutils & openssl both add some ARMv7-specific FPU optimization flags to gcc's command line which causes the binaries to SIGILL on ARMv6 processors. - The emacs, perl & ruby builds create machine-specific directories like `$out/libexec/emacs/25.1/armv6l-unknown-linux-gnueabihf` Both of these are now fixed. And no, unlike PER_LINUX32 (which makes `uname -m` report `i686` when run on x86_64) there is no kernel option to achieve the same thing for returning armv6l on a ARMv7. - Some packages like Xorg capture the kernel version where the build was done (it prints "Build Operating System: Linux 4.4.45 x86_64" to the logs). This improves binary reproducibility of such packages.
@dezgeg, thanks for your PR! By analyzing the history of the files in this pull request, we identified @Ericson2314, @errge and @edolstra to be potential reviewers. |
I was playing with a similar solution last week (https://github.com/expipiplus1/nixpkgs/blob/17c8652edbe164457e763d37cdaea03cd7251f91/pkgs/tools/misc/coreutils/uname-armv7l.patch) and discovered that (annoyingly) some packages use a system call to determine that machine instead of calling
@bennofs has suggested overriding the Edit, I misremembered who mentioned systemtap |
I'm not really in favor of this. It seems a bit hacky and adds considerable complexity to stdenv. (E.g. you have to be careful to ensure that fake-uname appears before coreutils' uname.) An alternative would be to patch coreutils' uname to return a deterministic value based on some environment variable (say (Actually the environment variable hack could also be done in Glibc's |
The glibc idea sounds good, I will give that a shot... |
Apparently that's not easy, as glibc build just auto-generates some wrappers from a system call list instead of having |
Oh, too bad :-( |
@dezgeg perhaps you can remove |
That seems too complex and risky for very little gain. For Go you can set Coreutils seems a better place to hack. |
I'd blacklist the system call itself at build time for sandboxed builds. Autodetection during configuration is rarely a good idea, period. Go wouldn't use glibc to do the system call anyways, would it? |
At least in the bootstrap Go |
/* node-name */ "localhost" | ||
/* kernel-release */ "4.4.0-not-a-real-version" | ||
/* kernel-version */ "#1 SMP PREEMPT Thu Jan 1 00:00:01 GMT 1970" | ||
/* machine */ (builtins.head (lib.splitString "-" stdenv.system)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the record, hostPlatform.system
is probably a better way to get what you want. Makes which of the 3 platforms you want explicit, and during cross compilation the stdenv.*
stuff incorrectly reflects the build platform.
Not sure if blacklisting is a good idea, but we could use @aszlig's seccomp patch for Nix to make the uname syscall return a different value. This would compensate for the lack of a |
If I remember correctly, besides optionally killing the process seccomp BPF filters can only affect the return value of a system call, not any values in userspace memory. |
@dezgeg: Well, you can via For example this was my WIP handler for rewriting the void rewriteStatHandler(int signo, siginfo_t *si, void *ctx) {
ucontext_t *uc = reinterpret_cast<ucontext_t*>(ctx);
if (signo != SIGSYS || si->si_code != SYS_SECCOMP || !uc)
throw SysError("unexpected SIGSYS triggered");
if (si->si_arch == SCMP_ARCH_X86_64) {
long ret = syscall(si->si_syscall,
uc->uc_mcontext.gregs[REG_RDI],
uc->uc_mcontext.gregs[REG_RSI]);
uc->uc_mcontext.gregs[REG_RAX] = ret;
if (ret != 0) return;
struct stat st;
memcpy(&st, &uc->uc_mcontext.gregs[REG_RSI], sizeof(st));
st.st_uid = 0;
st.st_gid = 0;
uc->uc_mcontext.gregs[REG_RSI] = reinterpret_cast<greg_t>(&st);
}
} So you can change any register with this, but because you're working on register-level you're also highly architecture dependant. Another reason why it's probably not a good idea is that seccomp also comes with a bit of overhead. |
By "blacklisting" I mean just fail the build. If killing the process is also easier / more performant, all the better! |
On darwin it would be really nice to have a fake |
We actually have a real sw_vers in Darwin.DarwinTools but a fake one might be useful too. |
Are there any updates on this pull request, please? |
@mmahut, @dezgeg suggested (
NixOS/nix#1916 (comment)) that it's
convenient to use a VM to do these builds (in lieu of this PR). @dezgeg, do
you have a one liner you can share for this?
…On Mon, 19 Aug 2019, 19:28 Marek Mahut, ***@***.***> wrote:
Are there any updates on this pull request, please?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#25240?email_source=notifications&email_token=AAGRJXHEWAHTF3PAEYXYZHDQFJ7XHA5CNFSM4DJCUB42YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4SSS5A#issuecomment-522529140>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAGRJXEA2FG3SFYXISYFTXDQFJ7XHANCNFSM4DJCUB4Q>
.
|
Thank you for your contributions.
|
There is this patch from Ubuntu folks and it works great: https://lists.ubuntu.com/archives/kernel-team/2016-January/068203.html { config, pkgs, ... }:
{
boot.kernelPatches = [
rec {
name = "compat_uts_machine";
patch = pkgs.fetchpatch {
inherit name;
url = "https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/jammy/patch/?id=c1da50fa6eddad313360249cadcd4905ac9f82ea";
sha256 = "sha256-mpq4YLhobWGs+TRKjIjoe5uDiYLVlimqWUCBGFH/zzU=";
};
}
];
boot.kernelParams = [
"compat_uts_machine=armv7l"
];
} [misuzu@oracle:~]$ uname -m
aarch64
[misuzu@oracle:~]$ linux32
[misuzu@oracle:~]$ uname -m
armv7l |
Is it still relevant? |
This PR seems stalled. Closing. |
A deterministic uname was finally added in #210102 |
This has two purity advantages:
This makes
uname -m
return the processor architecture we're buildingfor, not the architecture the build is running on. This mainly
affects ARM, where we want to build armv6l packages on an armv7l
package. The v7 processors are very capable of executing v6 code,
but many build systems will look at
uname -m
and decide to dodifferent things based on the result. Examples:
flags to gcc's command line which causes the binaries to SIGILL
on ARMv6 processors.
like
$out/libexec/emacs/25.1/armv6l-unknown-linux-gnueabihf
Both of these are now fixed. And no, unlike PER_LINUX32 (which
makes
uname -m
reporti686
when run on x86_64) there is no kerneloption to achieve the same thing for returning armv6l on a ARMv7.
Some packages like Xorg capture the kernel version where the build
was done (it prints "Build Operating System: Linux 4.4.45 x86_64"
to the logs). This improves binary reproducibility of such packages.
I've added this just for Linux for now (as it ended up requiring tweaking the bootstrap stages to get it right) but in principle it could be added for Darwin as well if there's a use case.
cc @edolstra