cmd/snap-update-ns: add C preamble for setns #3095

Merged
merged 27 commits into from Apr 11, 2017

Conversation

Projects
None yet
7 participants
Contributor

zyga commented Mar 28, 2017

This patch adds a preamble/bootstrap code to snap-update-ns so that it
can call setns(..., CLONE_NEWNS) before golang starts to create threads.

The setns(2) manual page states that CLONE_NEWNS fails if there are any
threads present, apart from the main thread.

The preamble has no access to command line arguments so it works around
this by probing /proc/self/cmdline and parsing this manually.

Signed-off-by: Zygmunt Krynicki zygmunt.krynicki@canonical.com

cmd/snap-update-ns/bootstrap.c
+ }
+ memset(buf, 0, buf_size);
+ ssize_t num_read;
+ if ((num_read = read(fd, buf, buf_size)) < 0) {
@niemeyer

niemeyer Mar 28, 2017

Contributor

More readable to have the read outside the if. Then, ideally this would also check:

if (num_read < 0 || num_read == sizeof buf_size)
@zyga

zyga Mar 29, 2017

Contributor

Tweaked

cmd/snap-update-ns/bootstrap.c
+ if (argv0_len == num_read) {
+ return NULL;
+ }
+ return &buf[argv0_len + 1];
@niemeyer

niemeyer Mar 28, 2017

Contributor

If \0 is the last byte, then argv_len < num_read, yet argv0_len+1 is an overrun.

@zyga

zyga Mar 29, 2017

Contributor

Corrected

cmd/snap-update-ns/bootstrap.c
+ // Find the name of the snap by scanning the cmdline. If there's no snap
+ // name given, just bail out. The go parts will scan this too.
+ const char* snap_name = find_snap_name(cmdline, sizeof cmdline, num_read);
+ if (*snap_name == '\0') {
@niemeyer

niemeyer Mar 28, 2017

Contributor

find_snap_name returns NULL.

Slightly worried about the rate of important errors in this logic. Please make sure to get a good second review.

@zyga

zyga Mar 29, 2017

Contributor

Ack, thank you for the first review, will do!

stolowski requested changes Mar 29, 2017 edited

A caveat - I'm not familiar with namespaces nor with the "big picture" for the problem this branch solves, so cannot comment on the approach and overall semantics. The code looks good with some general comments:

  • the read_cmdlne, find_snap_name, sanitize_snap_name should have tests (it may be neccessary to make /proc/../cmdline path mock-able/configurable for testing purposes).
  • [paranoid mode] if we want to be really paranoid, then we should be checking all system calls for errors, including close()
  • again, if we want to be really paranoid, we could cassert (just to be safe) on function arguments where it's critical for correct operation, such as making sure functions don't receive NULL for a buffer it operates on).
    [/paranoid mode]
+ *
+ */
+
+#include "bootstrap.h"
@morphis

morphis Mar 29, 2017

Contributor

Not really needed.

@zyga

zyga Mar 29, 2017

Contributor

Why not? This is standard practice to ensure that headers match implementation.

@morphis

morphis Mar 29, 2017

Contributor

Ah yeah, we're in C and not in C++, so makes more sense here to spot API/implementation differences.

+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
@morphis

morphis Mar 29, 2017

Contributor

Please add proper header guards

#ifndef SNAP_UPDATE_NS_BOOTSTRAP_H_
#define SNAP_UPDATE_NS_BOOTSTRAP_H_
[...]
#endif

@zyga

zyga Mar 29, 2017

Contributor

Ack, will do

@zyga

zyga Apr 3, 2017

Contributor

Done

cmd/snap-update-ns/bootstrap.h
+ *
+ */
+
+extern int bootstrap_errno;
@morphis

morphis Mar 29, 2017

Contributor

This one is only read from other code parts so a _get function is more what we want here.

@zyga

zyga Apr 3, 2017

Contributor

I decided not to, it's just more code that needs to be written where we want less code to exist.

cmd/snap-update-ns/bootstrap.h
+ */
+
+extern int bootstrap_errno;
+extern const char* bootstrap_msg;
@morphis

morphis Mar 29, 2017

Contributor

Same as for bootstrap_errno

@zyga

zyga Mar 29, 2017

Contributor

Not sure if this buys us anything. Would make the C code longer.

@morphis

morphis Mar 29, 2017

Contributor

Would just make the API contract clear. We don't support write, just read.

Contributor

jdstrand commented Mar 30, 2017

I'm struggling to see how update-ns being in Go is really saving us on complexity and maintenance when I see comments like this:

// Use a pre-main helper to switch the mount namespace. This is required as
// golang creates threads at will and setns(..., CLONE_NEWNS) fails if any
// threads apart from the main thread exist.

which is making us have to write C code to do the OS-level operations that are required.

Contributor

jdstrand commented Mar 30, 2017

In general, cmdline is something that is user-controlled. I understand that snapd is the caller of update-ns, but how are the arguments to update-ns created? Is it possible for a user to invoke a snap run command and manipulate cmdline? If so, this preamble code needs to be carefully written to handled untrusted input via cmdline.

Contributor

zyga commented Mar 30, 2017

@jdstrand to reply to your concerns:

The amount of system C code we need to write is minimal, it's really just one system call. The only complication is that we have no access to the command line in a convenient way and must execute this function before golang bootstrap begins, at which we no longer have one thread.

This program is not setuid root and does not process user input in C. The golang parts, which are significantly harder to attack, process content generated by snapd (the mount profile) based on what two participating snaps declare. Having said that at this level there is no user input parsed.

zyga added some commits Mar 28, 2017

cmd/snap-update-ns: add C preamble for setns
This patch adds a preamble/bootstrap code to snap-update-ns so that it
can call setns(..., CLONE_NEWNS) before golang starts to create threads.

The setns(2) manual page states that CLONE_NEWNS fails if there are any
threads present, apart from the main thread.

The preamble has no access to command line arguments so it works around
this by probing /proc/self/cmdline and parsing this manually.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: move C parts to separate file
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: move C code to dedicated files
The code was formatted with `clang-format -i -style=WebKit`

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: remove Go headers
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: handle argc == 1 better
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: do trivial validation of snap-name in C
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: add tests for C code
This patch adds unit tests for C code. There's some complexity here
because we effectively disable the bootstrap code to run on startup but
this will be restored later.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

Some questions and suggestions. Sorry that its slightly long :/

cmd/snap-update-ns/bootstrap.c
+ }
+ memset(buf, 0, buf_size);
+ ssize_t num_read = read(fd, buf, buf_size);
+ if (num_read < 0 || num_read == buf_size) {
@mvo5

mvo5 Apr 3, 2017

Collaborator

I wonder if it makes sense to have two different error messages here. It seems to me that num_read < 0 is a read releated error so that handling looks appropriate. However num_read == buf_size is a different kind of error, it means something like "internal error: buffer to read cmdline is too small" (right?). So maybe worth reporting separately.

@mvo5

mvo5 Apr 3, 2017

Collaborator

Actually - I'm slightly confused. In the case of num_read == buf_size the bootstrap_{errno,msg} are set. However in the later code its only an error if num_read is < 0 - is there code missing here that sets num_read = -1 if num_read == buf_size ? Or am I just misreading this code altogether :) ?

@zyga

zyga Apr 3, 2017

Contributor

Thanks, I'll tweak this accordingly. I think you are right.

cmd/snap-update-ns/bootstrap.c
+ bootstrap_errno = errno;
+ bootstrap_msg = "cannot read /proc/self/cmdline";
+ }
+ close(fd);
@mvo5

mvo5 Apr 3, 2017

Collaborator

Close may also return an error

@zyga

zyga Apr 3, 2017

Contributor

In practice it is an useless error that should not be checked for or handled. See: https://lwn.net/Articles/576478/

cmd/snap-update-ns/bootstrap.c
+
+// find_snap_name scans the command line buffer and looks for the 1st argument.
+const char*
+find_snap_name(char* buf, size_t buf_size, size_t num_read)
@mvo5

mvo5 Apr 3, 2017

Collaborator

Silly(?) question - but why do we need both buf_size and num_read here? Isn't num_read always smaller than buf_size and sufficient for the size checks in here?

@zyga

zyga Apr 3, 2017

Contributor

Just for simplicity and correctness, buf_size is a constant.

@mvo5

mvo5 Apr 3, 2017

Collaborator

Honest question, why is it simpler (and more correct) to use buf_size for the first check and num_read for the second? I mean, it seems checking for just num_read in the strnlen() is equally correct (and arguably simpler because when reading the code there is no need to ponder why in one place buf_size is used and in the other place num_read. Don't get me wrong, its fine, I'm just trying to understand the background a bit better.

@zyga

zyga Apr 3, 2017

Contributor

I think it is simpler because one argument is not a variable but a compile-time constant. I can fuse this into one variable if you want but I like the explicitness of "this is the size of the buffer" in C APIs.

@niemeyer

niemeyer Apr 6, 2017

Contributor

Having more logic to think about makes things more complex rather than simpler. If we should never go above the smaller number – and we shouldn't – there's no reason to have another number and make things any more complex.

Trivial and potentially serious (tomorrow) bug to introduce: invert the two parameters.

cmd/snap-update-ns/main.go
@@ -42,13 +44,19 @@ func main() {
func parseArgs(args []string) error {
parser := flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash|flags.PassAfterNonOption)
_, err := parser.ParseArgs(args)
- return err
+ if err != nil {
@mvo5

mvo5 Apr 3, 2017

Collaborator

This could be written as a single line: if _, err := parser.ParseArgs(args); err != nil {...

@zyga

zyga Apr 3, 2017

Contributor

Done

cmd/snap-update-ns/main.go
}
func run() error {
if err := parseArgs(os.Args[1:]); err != nil {
return err
}
-
+ if err := bootstrapError(); err != nil {
@mvo5

mvo5 Apr 3, 2017

Collaborator

Maybe a small comment here that that the bootstrap C code is automatically called and that we need to check errors for that here?

@zyga

zyga Apr 3, 2017

Contributor

Will do, thanks

@zyga

zyga Apr 3, 2017

Contributor

Done

zyga added some commits Apr 3, 2017

cmd/snap-update-ns: tweak everything to make testing work
This patch changes how the bootstrap code is enabled. I tried to make
several thins work (moving this to differnent packages, using multiple
consturctors with different prioritites and a flag variable) but it all
doesn't work because of how cgo linking works.

In absence of that, I just oped into a simple envirionment variable. I
use the value of SNAPD_INTERNAL and check for presence of
"x-switch-namespace=1," as a simple way to check if the bootstrap code
should work. It is easy to set this variable from snapd and we can now
unit test most of the boring C code easily.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: separate error conditions for buffer-full
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: simplify error propagation
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: explain bootstrap enale trick
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

zyga commented Apr 3, 2017

I updated this, tweaking slightly how initialization is done so that we can test more code. I added unit tests for what is reasonable to test this way (skipping the actual setns as that will be covered by spread). I can add a smoke spread test that just checks we setns correctly and reach the "not implemented" trigger (I will do that in a moment) but I'd like to land this and iterate.

+ bootstrap_msg = "cannot read /proc/self/cmdline";
+ } else if (num_read == buf_size) {
+ bootstrap_errno = 0;
+ bootstrap_msg = "cannot fit all of /proc/self/cmdline, buffer too small";
@mvo5

mvo5 Apr 3, 2017

Collaborator

I think this also needs to set num_read = -1 or else read_cmdline() will not fail in https://github.com/snapcore/snapd/pull/3095/files#diff-018c9af8a9874391aef7a2bfa0300d19R142 but carry on with an incorrect buffer.

cmd/snap-update-ns/bootstrap.c
+
+// find_snap_name scans the command line buffer and looks for the 1st argument.
+const char*
+find_snap_name(char* buf, size_t buf_size, size_t num_read)
@mvo5

mvo5 Apr 3, 2017

Collaborator

Silly(?) question - but why do we need both buf_size and num_read here? Isn't num_read always smaller than buf_size and sufficient for the size checks in here?

@zyga

zyga Apr 3, 2017

Contributor

Just for simplicity and correctness, buf_size is a constant.

@mvo5

mvo5 Apr 3, 2017

Collaborator

Honest question, why is it simpler (and more correct) to use buf_size for the first check and num_read for the second? I mean, it seems checking for just num_read in the strnlen() is equally correct (and arguably simpler because when reading the code there is no need to ponder why in one place buf_size is used and in the other place num_read. Don't get me wrong, its fine, I'm just trying to understand the background a bit better.

@zyga

zyga Apr 3, 2017

Contributor

I think it is simpler because one argument is not a variable but a compile-time constant. I can fuse this into one variable if you want but I like the explicitness of "this is the size of the buffer" in C APIs.

@niemeyer

niemeyer Apr 6, 2017

Contributor

Having more logic to think about makes things more complex rather than simpler. If we should never go above the smaller number – and we shouldn't – there's no reason to have another number and make things any more complex.

Trivial and potentially serious (tomorrow) bug to introduce: invert the two parameters.

cmd/snap-update-ns/bootstrap.c
+// on command line.
+void bootstrap(void)
+{
+// NOTE: This lets use use cgo/go to write tests without running the bulk
@mvo5

mvo5 Apr 3, 2017

Collaborator

Typo: This lets *us* use...

zyga added some commits Apr 3, 2017

cmd/snap-update-ns: return -1 if we cannot fit cmdline into buffer
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: fix typo
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
tests: add initial (partial) test for snap-update-ns
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: add Commentf for failing test
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: fix test to work with coverage
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

Looks good, thanks for the tests! Just one nitpick and one question, but not blockers.

cmd/snap-update-ns/bootstrap.c
+
+// sanitize_snap_name performs partial validation of the given name.
+// The goal is to ensure that there are no / or .. in the name.
+int sanitize_snap_name(const char* snap_name)
@stolowski

stolowski Apr 3, 2017

Contributor

Nitpick: wouldn't "validate" be a better name since this method doesn't actually alter the name in any way?

@zyga

zyga Apr 3, 2017

Contributor

Yes, good point. How about partially_validate_snap_name (to make it clear it's not a full validation)?

cmd/snap-update-ns/bootstrap.c
+// of the code automatically. In snapd we can just set the required
+// environment variable.
+#define TRIGGER_KEY "SNAPD_INTERNAL"
+#define TRIGGER_VAL "x-switch-namespace=1,"
@stolowski

stolowski Apr 3, 2017

Contributor

Is x-... some form of new convention we want to introduce with this PR? Do we use it elsewhere in snapd? Looks a little verbose.

@zyga

zyga Apr 3, 2017

Contributor

Ha, I was just trying to be generic, theSNAPD_INTERNAL variable could hold a list of comma-separated key-value pairs. I'm fine with reworking this in any way that we find suitable.

@stolowski

stolowski Apr 3, 2017

Contributor

I see. Ok, no arguing with that, just wanted to understand the reason ;)

@niemeyer

niemeyer Apr 6, 2017

Contributor

Something more straightforward would be nice indeed. How about

SNAPD_DEBUG_UPDATE_NS="skip-bootstrap"
@pedronis

pedronis Apr 6, 2017

Contributor

why not just have a bit of C code that sets a global no_bootstrap flag, that is compiled in only when building tests?

@zyga

zyga Apr 6, 2017

Contributor

Because cgo cannot be used in tests.

@pedronis

pedronis Apr 6, 2017

Contributor

you can use a file with a build tag though, no?

zyga added some commits Apr 3, 2017

cmd/snap-update-ns: rename sanitize to partially_validate
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

It looks good. A few more comments, and probably the last ones.

cmd/snap-update-ns/bootstrap.c
+
+// find_snap_name scans the command line buffer and looks for the 1st argument.
+const char*
+find_snap_name(char* buf, size_t buf_size, size_t num_read)
@mvo5

mvo5 Apr 3, 2017

Collaborator

Silly(?) question - but why do we need both buf_size and num_read here? Isn't num_read always smaller than buf_size and sufficient for the size checks in here?

@zyga

zyga Apr 3, 2017

Contributor

Just for simplicity and correctness, buf_size is a constant.

@mvo5

mvo5 Apr 3, 2017

Collaborator

Honest question, why is it simpler (and more correct) to use buf_size for the first check and num_read for the second? I mean, it seems checking for just num_read in the strnlen() is equally correct (and arguably simpler because when reading the code there is no need to ponder why in one place buf_size is used and in the other place num_read. Don't get me wrong, its fine, I'm just trying to understand the background a bit better.

@zyga

zyga Apr 3, 2017

Contributor

I think it is simpler because one argument is not a variable but a compile-time constant. I can fuse this into one variable if you want but I like the explicitness of "this is the size of the buffer" in C APIs.

@niemeyer

niemeyer Apr 6, 2017

Contributor

Having more logic to think about makes things more complex rather than simpler. If we should never go above the smaller number – and we shouldn't – there's no reason to have another number and make things any more complex.

Trivial and potentially serious (tomorrow) bug to introduce: invert the two parameters.

cmd/snap-update-ns/bootstrap.c
+// of the code automatically. In snapd we can just set the required
+// environment variable.
+#define TRIGGER_KEY "SNAPD_INTERNAL"
+#define TRIGGER_VAL "x-switch-namespace=1,"
@stolowski

stolowski Apr 3, 2017

Contributor

Is x-... some form of new convention we want to introduce with this PR? Do we use it elsewhere in snapd? Looks a little verbose.

@zyga

zyga Apr 3, 2017

Contributor

Ha, I was just trying to be generic, theSNAPD_INTERNAL variable could hold a list of comma-separated key-value pairs. I'm fine with reworking this in any way that we find suitable.

@stolowski

stolowski Apr 3, 2017

Contributor

I see. Ok, no arguing with that, just wanted to understand the reason ;)

@niemeyer

niemeyer Apr 6, 2017

Contributor

Something more straightforward would be nice indeed. How about

SNAPD_DEBUG_UPDATE_NS="skip-bootstrap"
@pedronis

pedronis Apr 6, 2017

Contributor

why not just have a bit of C code that sets a global no_bootstrap flag, that is compiled in only when building tests?

@zyga

zyga Apr 6, 2017

Contributor

Because cgo cannot be used in tests.

@pedronis

pedronis Apr 6, 2017

Contributor

you can use a file with a build tag though, no?

cmd/snap-update-ns/bootstrap.c
+#define TRIGGER_KEY "SNAPD_INTERNAL"
+#define TRIGGER_VAL "x-switch-namespace=1,"
+ const char* snapd_internal = getenv(TRIGGER_KEY);
+ if (snapd_internal == NULL || strstr(snapd_internal, TRIGGER_VAL) == NULL) {
@niemeyer

niemeyer Apr 6, 2017

Contributor

The logic here looks reversed. Bootstraping is the normal case, so the variable should be used to disable it instead, right?

@zyga

zyga Apr 6, 2017

Contributor

The problem is that we cannot say "don't bootstrap" from go. By the time go runs it's too late. I think it has to stay reversed.

@niemeyer

niemeyer Apr 6, 2017

Contributor

We don't want update-ns to require setting a debug flag to work at all, in the normal case.

cmd/snap-update-ns/bootstrap.c
+ // Find the name of the snap by scanning the cmdline. If there's no snap
+ // name given, just bail out. The go parts will scan this too.
+ const char* snap_name = find_snap_name(cmdline, sizeof cmdline, num_read);
+ if (snap_name == NULL || *snap_name == '\0') {
@niemeyer

niemeyer Apr 6, 2017

Contributor

The second case would be more safely handled inside find_snap_name. If it got an empty string, it didn't actually find a snap name.

@zyga

zyga Apr 6, 2017

Contributor

+1

+ // Look for known offenders in the snap name (.. and /) and do nothing if
+ // those are found. The golang code will validate snap name and print a
+ // proper error message but this just ensures we don't try to open / setns
+ // anything unusual.
@niemeyer

niemeyer Apr 6, 2017

Contributor

Nice.

cmd/snap-update-ns/bootstrap.go
+// findSnapName parses the argv-like array and finds the 1st argument.
+// Subsequent arguments are spearated by NUL-bytes.
+func findSnapName(buf []byte) *string {
+ if ptr := C.find_snap_name((*C.char)(unsafe.Pointer(&buf[0])), C.size_t(cap(buf)), C.size_t(len(buf))); ptr != nil {
@niemeyer

niemeyer Apr 6, 2017

Contributor

That doesn't look safe. That call is returning with ptr pointing to memory managed by Go's GC. If the memory moves, the function below will be accessing unknown memory. Instead, buf should be copied out into a malloc controlled buffer, defer free, and then passed into find_snap_name.

@zyga

zyga Apr 6, 2017

Contributor

+1

@zyga

zyga Apr 6, 2017

Contributor

On 2nd look I think this is correct:

The major change is the definition of rules for sharing Go pointers with C code, to ensure that such C code can coexist with Go's garbage collector. Briefly, Go and C may share memory allocated by Go when a pointer to that memory is passed to C as part of a cgo call, provided that the memory itself contains no pointers to Go-allocated memory, and provided that C does not retain the pointer after the call returns. These rules are checked by the runtime during program execution: if the runtime detects a violation, it prints a diagnosis and crashes the program. The checks can be disabled by setting the environment variable GODEBUG=cgocheck=0, but note that the vast majority of code identified by the checks is subtly incompatible with garbage collection in one way or another. Disabling the checks will typically only lead to more mysterious failure modes. Fixing the code in question should be strongly preferred over turning off the checks. See the cgo documentation for more details.

This is from cgo 1.6 release notes

@niemeyer

niemeyer Apr 6, 2017

Contributor

What I said above still seems true.

@niemeyer

niemeyer Apr 6, 2017

Contributor

Sorry, I think you are right. I was looking at the result of the function as if it was data that wouldn't be moved, but it's already a pointer, so if there's a move the GC will take it along as well.

cmd/snap-update-ns/bootstrap.go
+func findSnapName(buf []byte) *string {
+ if ptr := C.find_snap_name((*C.char)(unsafe.Pointer(&buf[0])), C.size_t(cap(buf)), C.size_t(len(buf))); ptr != nil {
+ str := C.GoString(ptr)
+ return &str
@niemeyer

niemeyer Apr 6, 2017

Contributor

*string is pretty unusual in Go. If we're wrapping, we can use Go's convention and return (string, error).

@zyga

zyga Apr 6, 2017

Contributor

(this is just for unit testing btw) I did it to be able to differentiate nil and "" as returned from find_snap_name. I wanted to avoid extra wrappers as the real intent is to test the C implementation, not provide a Go-like API for something that is not used in Go otherwise.

@niemeyer

niemeyer Apr 6, 2017

Contributor

You have extra wrappers already. It is Go code that is deciding when to return nil or &str.

Contributor

zyga commented Apr 6, 2017

Thank you for the review. I'll address the trivial bits ASAP but I think the fundamental question about how when to skip the bootstrap code needs to stay as-is. The problem is, as I mentioned above, that we cannot do anything from go to say "don't bootstrap" because the whole bootstrap code runs before any go starts. We need to not bootstrap by default and let snapd set something that would make the bootstrap happen. I made sure we don't miss this by always failing if the bootstrap code is skipped so that in production if we skip bootstrap (for whatever reason) we will fail without doing anything else.

zyga added some commits Apr 6, 2017

cmd/snap-update-ns: simplify find_snap_name
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: move trivial logic into find_snap_name
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

niemeyer commented Apr 6, 2017

Think outside the box. What hints you can use to decide not to bootstrap?

cmd/snap-update-ns: skip boostrap while testing, drop SNAPD_INTERNAL
This patch reverses the hack so that we now boostrap by default unless
the executable name ends with ".test". This makes SNAPD_INTERNAL hack
obsolete.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

zyga commented Apr 10, 2017

@niemeyer I've updated the bootstrap logic to look at argv0 and skip bootstrap automatically if it ends with ".test". There's no more SNAPD_INTERNAL hack needed.

LGTM, thanks for the changes. One trivial for a follow up:

cmd/snap-update-ns/bootstrap.c
+ return NULL;
+ }
+ char* snap_name = &buf[argv0_len + 1];
+ if (snap_name != NULL && *snap_name == '\0') {
@niemeyer

niemeyer Apr 11, 2017

Contributor

It can't possibly be NULL here.

@zyga

zyga Apr 11, 2017

Contributor

aha, good catch :-) I'll remove that and merge! :)

zyga added some commits Apr 11, 2017

cmd/snap-update-ns: remove pointless check
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

@zyga zyga merged commit eaba188 into snapcore:master Apr 11, 2017

6 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
xenial-amd64 autopkgtest finished (success)
Details
xenial-i386 autopkgtest finished (success)
Details
xenial-ppc64el autopkgtest finished (success)
Details
yakkety-amd64 autopkgtest finished (success)
Details
zesty-amd64 autopkgtest finished (success)
Details

@zyga zyga deleted the zyga:setns-on-startup branch Apr 12, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment