Skip to content
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

chrootenv: rewrite on top of GLib #33139

Merged
merged 1 commit into from Dec 31, 2017

Conversation

lukateras
Copy link
Member

@lukateras lukateras commented Dec 28, 2017

Changes:

  • doesn't handle root user separately
  • doesn't chdir("/") which makes using it seamless
  • only bind mounts, doesn't symlink

Incidentally, it fixes #33106.

It's about two times shorter than the previous version (it's even shorter than the Ruby version), and much, much easier to read/follow through. It uses GLib quite heavily, along with RAII (available in GCC/Clang).

Symlinking already happens in init script, so it's redundant to have it in this code. It has only been in chrootenv for a week, and I might reintroduce it back later.

About closure size: Steam itself uses GLib, so it won't result in a larger closure for most chrootenv users. It's also likely to be required by other programs. I've tested Steam, and of course, it still works.

/cc @Mic92 @dezgeg @srhb @pbogdan

@lukateras
Copy link
Member Author

lukateras commented Dec 28, 2017

I feel confident about new code and will merge on 31st if no one has any issues with it.

I should note that none of the changes to chrootenv are breaking buildFHSUserEnv behavior because root-specific logic was an optimization, and scripts that wrap chrootenv do chdir and symlink anyway.


else if (WIFSIGNALED(status))
kill(getpid(), WTERMSIG(status));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not obvious that the equivalent of return EX_OSERR; of the old version is unneeded in the new version: the signal that terminated the child process may be ignored by default and not terminate chrootenv.

Copy link
Member Author

@lukateras lukateras Dec 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If signal is ignored, chrootenv will return 0. This seems to be logical behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the child overrode the default of ignoring a signal and died on receiving it, it did not exit cleanly and chrootenv should not return 0.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, it's better to return 1 in this case. I've added it, see ac40a57.

@lukateras lukateras force-pushed the 20171228.053707/chrootenv branch 3 times, most recently from a0d1430 to 430476a Compare December 29, 2017 08:23
@FRidh
Copy link
Member

FRidh commented Dec 29, 2017

What do you think about documenting what this code is for and how it (roughly) works. I think each piece of code should explain why it is needed. So, what problem does this code solve?

Looking at the older version, there were some comments that helps the reader understand what is happening.

@lukateras
Copy link
Member Author

lukateras commented Dec 29, 2017

There are only two comments that still apply, specifically "Create new mount and user namespaces" and "Map users and groups to the parent namespace". I don't think these are particularly useful to keep around, because people who know about mount and user namespaces probably know about unshare anyway. If not, then man 2 unshare provides better documentation than these comments.

So, what problem does this code solve?

Setting up a chroot to ultimately run programs that assume a FHS-compliant environment.

@FRidh
Copy link
Member

FRidh commented Dec 29, 2017

Setting up a chroot to ultimately run programs that assume a FHS-compliant environment.

That at the very least should be included in the code header.

@lukateras
Copy link
Member Author

lukateras commented Dec 29, 2017

I'll add something like it to meta.description, thanks.

@dtzWill
Copy link
Member

dtzWill commented Dec 29, 2017

According to docs it seems g_error calls abort instead of exit which results in a coredump and is not intended for user-facing errors.

This seems inappropriate for at least the error path that prints messages to the user about running sysctl.

Maybe make a pass with this in mind, or instead adjust the g_perr macro to just log and exit instead?

@lukateras
Copy link
Member Author

lukateras commented Dec 29, 2017

abort is correct. Also, failed unshare might be a user configuration problem, or might be not, and coredump might be useful.

@dtzWill
Copy link
Member

dtzWill commented Dec 29, 2017

Not to bikeshed but I can't help but wonder how much of benefit glib brings here compared to C++ or something (g_autofree patterns, etc.)?

Regardless I'd appreciate, if for my curiosity if nothing else, a mention of the role glib plays in obtaining the improvements in this PR or to what extent they're orthogonal?

@lukateras
Copy link
Member Author

lukateras commented Dec 29, 2017

I think C++ is a bad language because it's very complex.

g_autofree is negligible convenience, and improvement mostly comes from utility functions: g_build_filename, g_mkdtemp_full (handles chmod), g_file_test, g_dir_open (doesn't return . and .. unlike opendir), g_strv_contains.

@dtzWill
Copy link
Member

dtzWill commented Dec 29, 2017

Okay, thanks for the comments and consideration of abort. LGTM review-wise.

@lukateras
Copy link
Member Author

Thanks for reviewing it!

#include <unistd.h>

#define g_perr(s, err) g_error("%s#L%d: %s: %s", __func__, __LINE__, s, g_strerror(err))
#define g_perrno(s) g_perr(s, errno)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

g_ is a glib namespace, you should not define names starting with g_.

Copy link
Member Author

@lukateras lukateras Dec 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, and names themselves are misleading (perror doesn't abort). I've pushed a new version with fail and fail_if macros: I think that separates concerns much better than previously used error macros, and names are much more straightforward. fail_if also cuts some boilerplate.

@lukateras lukateras force-pushed the 20171228.053707/chrootenv branch 2 times, most recently from a1182bd to 37da1a8 Compare December 30, 2017 18:26
Changes:

* doesn't handle root user separately
* doesn't chdir("/") which makes using it seamless
* only bind mounts, doesn't symlink (i.e. files)

Incidentally, fixes NixOS#33106.

It's about two times shorter than the previous version, and much
easier to read/follow through. It uses GLib quite heavily, along with
RAII (available in GCC/Clang).
Copy link
Member

@Mic92 Mic92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not tested the code itself, but the rest looks good to me.

@lukateras
Copy link
Member Author

lukateras commented Dec 31, 2017

@Mic92: Thanks for mentioning __cleanup__ GCC/Clang attribute on IRC!

@lukateras
Copy link
Member Author

lukateras commented Dec 31, 2017

@orivej: Thanks for the review!

I still want to implement a different order of messages in case of failed unshare, and the only clean way that I could come up with is via a SIGABRT or SIGTRAP handler. The problem is that if I use GLib logging from the handler, call to any logging function results in recursion warning and a subsequent abort (which is technically what I want to do anyway, but it doesn't let me print two messages).

@lukateras lukateras merged commit 60a133f into NixOS:master Dec 31, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

chrootenv: breaks when root contains broken symlink
6 participants