Merge lp:~jdstrand/snap-confine/coding-style into lp:~snappy-dev/snap-confine/trunk

Proposed by Jamie Strandboge
Status: Merged
Merged at revision: 101
Proposed branch: lp:~jdstrand/snap-confine/coding-style
Merge into: lp:~snappy-dev/snap-confine/trunk
Diff against target: 1493 lines (+706/-669)
8 files modified
Makefile (+4/-1)
debian/changelog (+4/-0)
debian/control (+1/-1)
src/Makefile (+20/-1)
src/main.c (+492/-490)
src/seccomp.c (+129/-122)
src/utils.c (+52/-50)
src/utils.h (+4/-4)
To merge this branch: bzr merge lp:~jdstrand/snap-confine/coding-style
Reviewer Review Type Date Requested Status
Michael Vogt (community) Approve
Review via email: mp+289781@code.launchpad.net

Description of the change

  * enforce coding style:
    - add syntax-check and fmt Makefile targets
    - use 'indent -linux'
    - debian/control: Build-Depends on indent

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote :

Looks great, thanks for this. Unfortunate that we loose the bzr blame info but thats life.

review: Approve
Revision history for this message
Jamie Strandboge (jdstrand) wrote :

hrmm, yes, oh well. Thanks!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2016-02-25 15:02:17 +0000
+++ Makefile 2016-03-22 12:19:24 +0000
@@ -8,5 +8,8 @@
8 make -C src $@8 make -C src $@
9 make -C tests $@9 make -C tests $@
1010
11check: all11syntax-check:
12 make -C src syntax-check
13
14check: all syntax-check
12 make -C tests test15 make -C tests test
1316
=== modified file 'debian/changelog'
--- debian/changelog 2016-03-22 11:23:59 +0000
+++ debian/changelog 2016-03-22 12:19:24 +0000
@@ -1,6 +1,10 @@
1ubuntu-core-launcher (1.0.21) UNRELEASED; urgency=medium1ubuntu-core-launcher (1.0.21) UNRELEASED; urgency=medium
2 * src/main.c: setup private /dev/pts2 * src/main.c: setup private /dev/pts
3 * debian/usr.bin.ubuntu-core-launcher: allow mounting /dev/pts3 * debian/usr.bin.ubuntu-core-launcher: allow mounting /dev/pts
4 * enforce coding style:
5 - add syntax-check and fmt Makefile targets
6 - use 'indent -linux'
7 - debian/control: Build-Depends on indent
48
5 -- Jamie Strandboge <jamie@ubuntu.com> Tue, 22 Mar 2016 06:23:38 -05009 -- Jamie Strandboge <jamie@ubuntu.com> Tue, 22 Mar 2016 06:23:38 -0500
610
711
=== modified file 'debian/control'
--- debian/control 2016-01-26 15:11:20 +0000
+++ debian/control 2016-03-22 12:19:24 +0000
@@ -2,7 +2,7 @@
2Section: utils2Section: utils
3Priority: optional3Priority: optional
4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
5Build-Depends: debhelper (>= 9), libseccomp-dev, libapparmor-dev, libudev-dev, dh-apparmor5Build-Depends: debhelper (>= 9), libseccomp-dev, libapparmor-dev, libudev-dev, dh-apparmor, indent
6Standards-Version: 3.9.66Standards-Version: 3.9.6
7Vcs-Bzr: lp:~snappy-dev/ubuntu-core-launcher/trunk7Vcs-Bzr: lp:~snappy-dev/ubuntu-core-launcher/trunk
88
99
=== modified file 'src/Makefile'
--- src/Makefile 2015-05-06 11:26:07 +0000
+++ src/Makefile 2016-03-22 12:19:24 +0000
@@ -2,8 +2,11 @@
2CFLAGS= -D_GNU_SOURCE -O2 -Wall -Werror $(shell dpkg-buildflags --get CFLAGS)2CFLAGS= -D_GNU_SOURCE -O2 -Wall -Werror $(shell dpkg-buildflags --get CFLAGS)
3LD_FLAGS = $(shell dpkg-buildflags --get LDFLAGS)3LD_FLAGS = $(shell dpkg-buildflags --get LDFLAGS)
4LIBS = -lapparmor -lseccomp -ludev4LIBS = -lapparmor -lseccomp -ludev
5TMPDIR = ./tmp
6FMT = indent -linux
57
6BIN = ubuntu-core-launcher8BIN = ubuntu-core-launcher
9HDRS = $(wildcard *.h)
7SRCS = $(wildcard *.c)10SRCS = $(wildcard *.c)
8OBJS = $(SRCS:.c=.o)11OBJS = $(SRCS:.c=.o)
912
@@ -15,7 +18,23 @@
1518
16distclean: clean19distclean: clean
17clean:20clean:
18 rm -f *.o ${BIN}21 rm -f *.o $(BIN) *~
22 rm -rf $(TMPDIR)
23
24fmt:
25 for f in $(HDRS) $(SRCS); do \
26 echo "$(FMT) $$f ... "; \
27 $(FMT) "$$f"; \
28 done; \
29
30syntax-check:
31 $(shell mkdir $(TMPDIR) 2>/dev/null)
32 for f in $(HDRS) $(SRCS); do \
33 out=$(TMPDIR)/$$f.out; \
34 echo "Checking '$(FMT) $$f' ... "; \
35 $(FMT) "$$f" -o "$$out"; \
36 diff -Naur "$$f" "$$out" || exit 1; \
37 done; \
1938
20install:39install:
21 # create dirs40 # create dirs
2241
=== modified file 'src/main.c'
--- src/main.c 2016-03-21 17:33:08 +0000
+++ src/main.c 2016-03-22 12:19:24 +0000
@@ -41,498 +41,500 @@
4141
42#define MAX_BUF 100042#define MAX_BUF 1000
4343
44bool verify_appname(const char *appname) {44bool verify_appname(const char *appname)
45 // these chars are allowed in a appname45{
46 const char* whitelist_re = "^[a-z0-9][a-z0-9+._-]+$";46 // these chars are allowed in a appname
47 regex_t re;47 const char *whitelist_re = "^[a-z0-9][a-z0-9+._-]+$";
48 if (regcomp(&re, whitelist_re, REG_EXTENDED|REG_NOSUB) != 0)48 regex_t re;
49 die("can not compile regex %s", whitelist_re);49 if (regcomp(&re, whitelist_re, REG_EXTENDED | REG_NOSUB) != 0)
5050 die("can not compile regex %s", whitelist_re);
51 int status = regexec(&re, appname, 0, NULL, 0);51
52 regfree(&re);52 int status = regexec(&re, appname, 0, NULL, 0);
5353 regfree(&re);
54 return (status == 0);54
55}55 return (status == 0);
5656}
57void run_snappy_app_dev_add(struct udev *u, const char *path, const char *appname) {57
58 debug("run_snappy_app_dev_add: %s %s", path, appname);58void run_snappy_app_dev_add(struct udev *u, const char *path,
59 struct udev_device *d = udev_device_new_from_syspath(u, path);59 const char *appname)
60 if (d == NULL)60{
61 die("can not find %s", path);61 debug("run_snappy_app_dev_add: %s %s", path, appname);
62 dev_t devnum = udev_device_get_devnum (d);62 struct udev_device *d = udev_device_new_from_syspath(u, path);
63 udev_device_unref(d);63 if (d == NULL)
6464 die("can not find %s", path);
65 int status = 0;65 dev_t devnum = udev_device_get_devnum(d);
66 pid_t pid = fork();66 udev_device_unref(d);
67 if (pid == 0) {67
68 char buf[64];68 int status = 0;
69 unsigned major = MAJOR(devnum);69 pid_t pid = fork();
70 unsigned minor = MINOR(devnum);70 if (pid == 0) {
71 must_snprintf(buf, sizeof(buf), "%u:%u", major, minor);71 char buf[64];
72 if(execl("/lib/udev/snappy-app-dev", "/lib/udev/snappy-app-dev", "add", appname, path, buf, NULL) != 0)72 unsigned major = MAJOR(devnum);
73 die("execlp failed");73 unsigned minor = MINOR(devnum);
74 }74 must_snprintf(buf, sizeof(buf), "%u:%u", major, minor);
75 if(waitpid(pid, &status, 0) < 0)75 if (execl
76 die("waitpid failed");76 ("/lib/udev/snappy-app-dev", "/lib/udev/snappy-app-dev",
77 if(WIFEXITED(status) && WEXITSTATUS(status) != 0)77 "add", appname, path, buf, NULL) != 0)
78 die("child exited with status %i", WEXITSTATUS(status));78 die("execlp failed");
79 else if(WIFSIGNALED(status))79 }
80 die("child died with signal %i", WTERMSIG(status));80 if (waitpid(pid, &status, 0) < 0)
81}81 die("waitpid failed");
8282 if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
83void setup_udev_snappy_assign(const char *appname) {83 die("child exited with status %i", WEXITSTATUS(status));
84 debug("setup_udev_snappy_assign");84 else if (WIFSIGNALED(status))
8585 die("child died with signal %i", WTERMSIG(status));
86 struct udev *u = udev_new();86}
87 if (u == NULL)87
88 die("udev_new failed");88void setup_udev_snappy_assign(const char *appname)
8989{
90 const char* static_devices[] = {90 debug("setup_udev_snappy_assign");
91 "/sys/class/mem/null",91
92 "/sys/class/mem/full",92 struct udev *u = udev_new();
93 "/sys/class/mem/zero",93 if (u == NULL)
94 "/sys/class/mem/random",94 die("udev_new failed");
95 "/sys/class/mem/urandom",95
96 "/sys/class/tty/tty",96 const char *static_devices[] = {
97 "/sys/class/tty/console",97 "/sys/class/mem/null",
98 "/sys/class/tty/ptmx",98 "/sys/class/mem/full",
99 NULL,99 "/sys/class/mem/zero",
100 };100 "/sys/class/mem/random",
101 int i;101 "/sys/class/mem/urandom",
102 for(i=0; static_devices[i] != NULL; i++) {102 "/sys/class/tty/tty",
103 run_snappy_app_dev_add(u, static_devices[i], appname);103 "/sys/class/tty/console",
104 }104 "/sys/class/tty/ptmx",
105105 NULL,
106 struct udev_enumerate *devices = udev_enumerate_new(u);106 };
107 if (devices == NULL)107 int i;
108 die("udev_enumerate_new failed");108 for (i = 0; static_devices[i] != NULL; i++) {
109109 run_snappy_app_dev_add(u, static_devices[i], appname);
110 if (udev_enumerate_add_match_tag (devices, "snappy-assign") != 0)110 }
111 die("udev_enumerate_add_match_tag");111
112112 struct udev_enumerate *devices = udev_enumerate_new(u);
113 if(udev_enumerate_add_match_property (devices, "SNAPPY_APP", appname) != 0)113 if (devices == NULL)
114 die("udev_enumerate_add_match_property");114 die("udev_enumerate_new failed");
115115
116 if(udev_enumerate_scan_devices(devices) != 0)116 if (udev_enumerate_add_match_tag(devices, "snappy-assign") != 0)
117 die("udev_enumerate_scan failed");117 die("udev_enumerate_add_match_tag");
118118
119 struct udev_list_entry *l = udev_enumerate_get_list_entry (devices);119 if (udev_enumerate_add_match_property(devices, "SNAPPY_APP", appname) !=
120 while (l != NULL) {120 0)
121 const char *path = udev_list_entry_get_name (l);121 die("udev_enumerate_add_match_property");
122 if (path == NULL)122
123 die("udev_list_entry_get_name failed");123 if (udev_enumerate_scan_devices(devices) != 0)
124 run_snappy_app_dev_add(u, path, appname);124 die("udev_enumerate_scan failed");
125 l = udev_list_entry_get_next(l);125
126 }126 struct udev_list_entry *l = udev_enumerate_get_list_entry(devices);
127127 while (l != NULL) {
128 udev_enumerate_unref(devices);128 const char *path = udev_list_entry_get_name(l);
129 udev_unref(u);129 if (path == NULL)
130}130 die("udev_list_entry_get_name failed");
131131 run_snappy_app_dev_add(u, path, appname);
132void setup_devices_cgroup(const char *appname) {132 l = udev_list_entry_get_next(l);
133 debug("setup_devices_cgroup");133 }
134134
135 // extra paranoia135 udev_enumerate_unref(devices);
136 if(!verify_appname(appname))136 udev_unref(u);
137 die("appname %s not allowed", appname);137}
138138
139 // create devices cgroup controller139void setup_devices_cgroup(const char *appname)
140 char cgroup_dir[PATH_MAX];140{
141 must_snprintf(cgroup_dir, sizeof(cgroup_dir), "/sys/fs/cgroup/devices/snappy.%s/", appname);141 debug("setup_devices_cgroup");
142142
143 if (mkdir(cgroup_dir, 0755) < 0 && errno != EEXIST)143 // extra paranoia
144 die("mkdir failed");144 if (!verify_appname(appname))
145145 die("appname %s not allowed", appname);
146 // move ourselves into it146
147 char cgroup_file[PATH_MAX];147 // create devices cgroup controller
148 must_snprintf(cgroup_file, sizeof(cgroup_file), "%s%s", cgroup_dir, "tasks");148 char cgroup_dir[PATH_MAX];
149149 must_snprintf(cgroup_dir, sizeof(cgroup_dir),
150 char buf[128];150 "/sys/fs/cgroup/devices/snappy.%s/", appname);
151 must_snprintf(buf, sizeof(buf), "%i", getpid());151
152 write_string_to_file(cgroup_file, buf);152 if (mkdir(cgroup_dir, 0755) < 0 && errno != EEXIST)
153153 die("mkdir failed");
154 // deny by default154
155 must_snprintf(cgroup_file, sizeof(cgroup_file), "%s%s", cgroup_dir, "devices.deny");155 // move ourselves into it
156 write_string_to_file(cgroup_file, "a");156 char cgroup_file[PATH_MAX];
157157 must_snprintf(cgroup_file, sizeof(cgroup_file), "%s%s", cgroup_dir,
158}158 "tasks");
159159
160bool snappy_udev_setup_required(const char *appname) {160 char buf[128];
161 debug("snappy_udev_setup_required");161 must_snprintf(buf, sizeof(buf), "%i", getpid());
162162 write_string_to_file(cgroup_file, buf);
163 // extra paranoia163
164 if(!verify_appname(appname))164 // deny by default
165 die("appname %s not allowed", appname);165 must_snprintf(cgroup_file, sizeof(cgroup_file), "%s%s", cgroup_dir,
166166 "devices.deny");
167 char override_file[PATH_MAX];167 write_string_to_file(cgroup_file, "a");
168 must_snprintf(override_file, sizeof(override_file), "/var/lib/apparmor/clicks/%s.json.additional", appname);168
169169}
170 // if a snap package gets unrestricted apparmor access we need to setup170
171 // a device cgroup.171bool snappy_udev_setup_required(const char *appname)
172 //172{
173 // the "needle" string is what gives this access so we search for that173 debug("snappy_udev_setup_required");
174 // here174
175 const char *needle =175 // extra paranoia
176 "{" "\n"176 if (!verify_appname(appname))
177 " \"write_path\": [" "\n"177 die("appname %s not allowed", appname);
178 " \"/dev/**\"" "\n"178
179 " ]," "\n"179 char override_file[PATH_MAX];
180 " \"read_path\": [" "\n"180 must_snprintf(override_file, sizeof(override_file),
181 " \"/run/udev/data/*\"" "\n"181 "/var/lib/apparmor/clicks/%s.json.additional", appname);
182 " ]\n"182
183 "}";183 // if a snap package gets unrestricted apparmor access we need to setup
184 debug("looking for: '%s'", needle);184 // a device cgroup.
185 char content[strlen(needle)];185 //
186186 // the "needle" string is what gives this access so we search for that
187 int fd = open(override_file, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);187 // here
188 if (fd < 0)188 const char *needle =
189 return false;189 "{" "\n"
190 int n = read(fd, content, sizeof(content));190 " \"write_path\": [" "\n"
191 close(fd);191 " \"/dev/**\"" "\n"
192 if (n < sizeof(content))192 " ]," "\n"
193 return false;193 " \"read_path\": [" "\n" " \"/run/udev/data/*\"" "\n" " ]\n" "}";
194194 debug("looking for: '%s'", needle);
195 // memcpy so that we don't have to deal with \0 in the input195 char content[strlen(needle)];
196 if (memcmp(content, needle, strlen(needle)) == 0) {196
197 debug("found needle, need to apply udev setup");197 int fd = open(override_file, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
198 return true;198 if (fd < 0)
199 }199 return false;
200200 int n = read(fd, content, sizeof(content));
201 return false;201 close(fd);
202}202 if (n < sizeof(content))
203203 return false;
204bool is_running_on_classic_ubuntu() {204
205 return (access("/var/lib/dpkg/status", F_OK) == 0);205 // memcpy so that we don't have to deal with \0 in the input
206}206 if (memcmp(content, needle, strlen(needle)) == 0) {
207207 debug("found needle, need to apply udev setup");
208void setup_private_mount(const char* appname) {208 return true;
209 uid_t uid = getuid();209 }
210 gid_t gid = getgid();210
211 char tmpdir[MAX_BUF] = {0};211 return false;
212212}
213 // Create a 0700 base directory, this is the base dir that is213
214 // protected from other users.214bool is_running_on_classic_ubuntu()
215 //215{
216 // Under that basedir, we put a 1777 /tmp dir that is then bind216 return (access("/var/lib/dpkg/status", F_OK) == 0);
217 // mounted for the applications to use217}
218 must_snprintf(tmpdir, sizeof(tmpdir), "/tmp/snap.%d_%s_XXXXXX", uid, appname);218
219 if (mkdtemp(tmpdir) == NULL) {219void setup_private_mount(const char *appname)
220 die("unable to create tmpdir");220{
221 }221 uid_t uid = getuid();
222222 gid_t gid = getgid();
223 // now we create a 1777 /tmp inside our private dir223 char tmpdir[MAX_BUF] = { 0 };
224 mode_t old_mask = umask(0);224
225 char *d = strdup(tmpdir);225 // Create a 0700 base directory, this is the base dir that is
226 if (!d) {226 // protected from other users.
227 die("Out of memory");227 //
228 }228 // Under that basedir, we put a 1777 /tmp dir that is then bind
229 must_snprintf(tmpdir, sizeof(tmpdir), "%s/tmp", d);229 // mounted for the applications to use
230 free(d);230 must_snprintf(tmpdir, sizeof(tmpdir), "/tmp/snap.%d_%s_XXXXXX", uid,
231231 appname);
232 if (mkdir(tmpdir, 01777) != 0) {232 if (mkdtemp(tmpdir) == NULL) {
233 die("unable to create /tmp inside private dir");233 die("unable to create tmpdir");
234 }234 }
235 umask(old_mask);235 // now we create a 1777 /tmp inside our private dir
236236 mode_t old_mask = umask(0);
237 // MS_BIND is there from linux 2.4237 char *d = strdup(tmpdir);
238 if (mount(tmpdir, "/tmp", NULL, MS_BIND, NULL) != 0) {238 if (!d) {
239 die("unable to bind private /tmp");239 die("Out of memory");
240 }240 }
241 // MS_PRIVATE needs linux > 2.6.11241 must_snprintf(tmpdir, sizeof(tmpdir), "%s/tmp", d);
242 if (mount("none", "/tmp", NULL, MS_PRIVATE, NULL) != 0) {242 free(d);
243 die("unable to make /tmp/ private");243
244 }244 if (mkdir(tmpdir, 01777) != 0) {
245245 die("unable to create /tmp inside private dir");
246 // do the chown after the bind mount to avoid potential shenanigans246 }
247 if (chown("/tmp/", uid, gid) < 0) {247 umask(old_mask);
248 die("unable to chown tmpdir");248
249 }249 // MS_BIND is there from linux 2.4
250250 if (mount(tmpdir, "/tmp", NULL, MS_BIND, NULL) != 0) {
251 // ensure we set the various TMPDIRs to our newly created tmpdir251 die("unable to bind private /tmp");
252 const char *tmpd[] = {"TMPDIR", "TEMPDIR", "SNAP_APP_TMPDIR", NULL};252 }
253 int i;253 // MS_PRIVATE needs linux > 2.6.11
254 for (i=0; tmpd[i] != NULL; i++) {254 if (mount("none", "/tmp", NULL, MS_PRIVATE, NULL) != 0) {
255 if (setenv(tmpd[i], "/tmp", 1) != 0) {255 die("unable to make /tmp/ private");
256 die("unable to set '%s'", tmpd[i]);256 }
257 }257 // do the chown after the bind mount to avoid potential shenanigans
258 }258 if (chown("/tmp/", uid, gid) < 0) {
259}259 die("unable to chown tmpdir");
260260 }
261void setup_private_pts() {261 // ensure we set the various TMPDIRs to our newly created tmpdir
262 // See https://www.kernel.org/doc/Documentation/filesystems/devpts.txt262 const char *tmpd[] = { "TMPDIR", "TEMPDIR", "SNAP_APP_TMPDIR", NULL };
263 //263 int i;
264 // Ubuntu by default uses devpts 'single-instance' mode where /dev/pts/ptmx264 for (i = 0; tmpd[i] != NULL; i++) {
265 // is mounted with ptmxmode=0000. We don't want to change the startup265 if (setenv(tmpd[i], "/tmp", 1) != 0) {
266 // scripts though, so we follow the instructions in point '4' of266 die("unable to set '%s'", tmpd[i]);
267 // 'User-space changes' in the above doc. In other words, after267 }
268 // unshare(CLONE_NEWNS), we mount devpts with -o newinstance,ptmxmode=0666268 }
269 // and then bind mount /dev/pts/ptmx onto /dev/ptmx269}
270270
271 struct stat st;271void setup_private_pts()
272272{
273 // Make sure /dev/pts/ptmx exists, otherwise we are in legacy mode which273 // See https://www.kernel.org/doc/Documentation/filesystems/devpts.txt
274 // doesn't provide the isolation we require.274 //
275 if (stat("/dev/pts/ptmx", &st) != 0) {275 // Ubuntu by default uses devpts 'single-instance' mode where /dev/pts/ptmx
276 die("/dev/pts/ptmx does not exist");276 // is mounted with ptmxmode=0000. We don't want to change the startup
277 }277 // scripts though, so we follow the instructions in point '4' of
278 // Make sure /dev/ptmx exists so we can bind mount over it278 // 'User-space changes' in the above doc. In other words, after
279 if (stat("/dev/ptmx", &st) != 0) {279 // unshare(CLONE_NEWNS), we mount devpts with -o newinstance,ptmxmode=0666
280 die("/dev/ptmx does not exist");280 // and then bind mount /dev/pts/ptmx onto /dev/ptmx
281 }281
282282 struct stat st;
283 // Since multi-instance, use ptmxmode=0666. The other options are copied283
284 // from /etc/default/devpts284 // Make sure /dev/pts/ptmx exists, otherwise we are in legacy mode which
285 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,285 // doesn't provide the isolation we require.
286 "newinstance,ptmxmode=0666,mode=0620,gid=5")) {286 if (stat("/dev/pts/ptmx", &st) != 0) {
287 die("unable to mount a new instance of '/dev/pts'");287 die("/dev/pts/ptmx does not exist");
288 }288 }
289289 // Make sure /dev/ptmx exists so we can bind mount over it
290 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {290 if (stat("/dev/ptmx", &st) != 0) {
291 die("unable to mount '/dev/pts/ptmx'->'/dev/ptmx'");291 die("/dev/ptmx does not exist");
292 }292 }
293}293 // Since multi-instance, use ptmxmode=0666. The other options are copied
294294 // from /etc/default/devpts
295void setup_snappy_os_mounts() {295 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
296 debug("setup_snappy_os_mounts()\n");296 "newinstance,ptmxmode=0666,mode=0620,gid=5")) {
297297 die("unable to mount a new instance of '/dev/pts'");
298 // FIXME: hardcoded "ubuntu-core.*"298 }
299 glob_t glob_res;299
300 if (glob("/snaps/ubuntu-core*/current/", 0, NULL, &glob_res) != 0) {300 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
301 die("can not find a snappy os");301 die("unable to mount '/dev/pts/ptmx'->'/dev/ptmx'");
302 }302 }
303 if ((glob_res.gl_pathc =! 1)) {303}
304 die("expected 1 os snap, found %i", (int)glob_res.gl_pathc);304
305 }305void setup_snappy_os_mounts()
306 char *mountpoint = glob_res.gl_pathv[0];306{
307307 debug("setup_snappy_os_mounts()\n");
308 // we mount some whitelisted directories308
309 //309 // FIXME: hardcoded "ubuntu-core.*"
310 // Note that we do not mount "/etc/" from snappy. We could do that,310 glob_t glob_res;
311 // but if we do we need to ensure that data like /etc/{hostname,hosts,311 if (glob("/snaps/ubuntu-core*/current/", 0, NULL, &glob_res) != 0) {
312 // passwd,groups} is in sync between the two systems (probably via312 die("can not find a snappy os");
313 // selected bind mounts of those files).313 }
314 const char *mounts[] = {"/bin", "/sbin", "/lib", "/lib64", "/usr"};314 if ((glob_res.gl_pathc = !1)) {
315 for (int i=0; i < sizeof(mounts)/sizeof(char*); i++) {315 die("expected 1 os snap, found %i", (int)glob_res.gl_pathc);
316 // we mount the OS snap /bin over the real /bin in this NS316 }
317 const char *dst = mounts[i];317 char *mountpoint = glob_res.gl_pathv[0];
318318
319 char buf[512];319 // we mount some whitelisted directories
320 must_snprintf(buf, sizeof(buf), "%s%s", mountpoint, dst);320 //
321 const char *src = buf;321 // Note that we do not mount "/etc/" from snappy. We could do that,
322322 // but if we do we need to ensure that data like /etc/{hostname,hosts,
323 debug("mounting %s -> %s\n", src, dst);323 // passwd,groups} is in sync between the two systems (probably via
324 if (mount(src, dst, NULL, MS_BIND, NULL) != 0) {324 // selected bind mounts of those files).
325 die("unable to bind %s to %s", src, dst);325 const char *mounts[] = { "/bin", "/sbin", "/lib", "/lib64", "/usr" };
326 }326 for (int i = 0; i < sizeof(mounts) / sizeof(char *); i++) {
327 }327 // we mount the OS snap /bin over the real /bin in this NS
328328 const char *dst = mounts[i];
329 globfree(&glob_res);329
330}330 char buf[512];
331331 must_snprintf(buf, sizeof(buf), "%s%s", mountpoint, dst);
332void setup_slave_mount_namespace() {332 const char *src = buf;
333 // unshare() and CLONE_NEWNS require linux >= 2.6.16 and glibc >= 2.14333
334 // if using an older glibc, you'd need -D_BSD_SOURCE or -D_SVID_SORUCE.334 debug("mounting %s -> %s\n", src, dst);
335 if (unshare(CLONE_NEWNS) < 0) {335 if (mount(src, dst, NULL, MS_BIND, NULL) != 0) {
336 die("unable to set up mount namespace");336 die("unable to bind %s to %s", src, dst);
337 }337 }
338338 }
339 // make our "/" a rslave of the real "/". this means that339
340 // mounts from the host "/" get propagated to our namespace340 globfree(&glob_res);
341 // (i.e. we see new media mounts)341}
342 if (mount("none", "/", NULL, MS_REC|MS_SLAVE, NULL) != 0) {342
343 die("can not make make / rslave");343void setup_slave_mount_namespace()
344 }344{
345}345 // unshare() and CLONE_NEWNS require linux >= 2.6.16 and glibc >= 2.14
346346 // if using an older glibc, you'd need -D_BSD_SOURCE or -D_SVID_SORUCE.
347void mkpath(const char *const path) {347 if (unshare(CLONE_NEWNS) < 0) {
348 // If asked to create an empty path, return immediately.348 die("unable to set up mount namespace");
349 if (strlen(path) == 0) {349 }
350 return;350 // make our "/" a rslave of the real "/". this means that
351 }351 // mounts from the host "/" get propagated to our namespace
352352 // (i.e. we see new media mounts)
353 // We're going to use strtok_r, which needs to modify the path, so we'll make353 if (mount("none", "/", NULL, MS_REC | MS_SLAVE, NULL) != 0) {
354 // a copy of it.354 die("can not make make / rslave");
355 char *path_copy = strdup(path);355 }
356 if (path_copy == NULL) {356}
357 die("failed to create user data directory");357
358 }358void mkpath(const char *const path)
359359{
360 // Open flags to use while we walk the user data path:360 // If asked to create an empty path, return immediately.
361 // - Don't follow symlinks361 if (strlen(path) == 0) {
362 // - Don't allow child access to file descriptor362 return;
363 // - Only open a directory (fail otherwise)363 }
364 int open_flags = O_NOFOLLOW | O_CLOEXEC | O_DIRECTORY;364 // We're going to use strtok_r, which needs to modify the path, so we'll make
365365 // a copy of it.
366 // We're going to create each path segment via openat/mkdirat calls instead366 char *path_copy = strdup(path);
367 // of mkdir calls, to avoid following symlinks and placing the user data367 if (path_copy == NULL) {
368 // directory somewhere we never intended for it to go. The first step is to368 die("failed to create user data directory");
369 // get an initial file descriptor.369 }
370 int fd = AT_FDCWD;370 // Open flags to use while we walk the user data path:
371 if (path_copy[0] == '/') {371 // - Don't follow symlinks
372 fd = open("/", open_flags);372 // - Don't allow child access to file descriptor
373 if (fd < 0) {373 // - Only open a directory (fail otherwise)
374 free(path_copy);374 int open_flags = O_NOFOLLOW | O_CLOEXEC | O_DIRECTORY;
375 die("failed to create user data directory");375
376 }376 // We're going to create each path segment via openat/mkdirat calls instead
377 }377 // of mkdir calls, to avoid following symlinks and placing the user data
378378 // directory somewhere we never intended for it to go. The first step is to
379 // strtok_r needs a pointer to keep track of where it is in the string.379 // get an initial file descriptor.
380 char *path_walker;380 int fd = AT_FDCWD;
381381 if (path_copy[0] == '/') {
382 // Initialize tokenizer and obtain first path segment.382 fd = open("/", open_flags);
383 char *path_segment = strtok_r(path_copy, "/", &path_walker);383 if (fd < 0) {
384 while (path_segment) {384 free(path_copy);
385 // Try to create the directory. It's okay if it already existed, but any385 die("failed to create user data directory");
386 // other error is fatal.386 }
387 if (mkdirat(fd, path_segment, 0755) < 0 && errno != EEXIST) {387 }
388 close(fd);388 // strtok_r needs a pointer to keep track of where it is in the string.
389 free(path_copy);389 char *path_walker;
390 die("failed to create user data directory");390
391 }391 // Initialize tokenizer and obtain first path segment.
392392 char *path_segment = strtok_r(path_copy, "/", &path_walker);
393 // Open the parent directory we just made (and close the previous one) so393 while (path_segment) {
394 // we can continue down the path.394 // Try to create the directory. It's okay if it already existed, but any
395 int previous_fd = fd;395 // other error is fatal.
396 fd = openat(fd, path_segment, open_flags);396 if (mkdirat(fd, path_segment, 0755) < 0 && errno != EEXIST) {
397 close(previous_fd);397 close(fd);
398 if (fd < 0) {398 free(path_copy);
399 free(path_copy);399 die("failed to create user data directory");
400 die("failed to create user data directory");400 }
401 }401 // Open the parent directory we just made (and close the previous one) so
402402 // we can continue down the path.
403 // Obtain the next path segment.403 int previous_fd = fd;
404 path_segment = strtok_r(NULL, "/", &path_walker);404 fd = openat(fd, path_segment, open_flags);
405 }405 close(previous_fd);
406406 if (fd < 0) {
407 // Close the descriptor for the final directory in the path.407 free(path_copy);
408 close(fd);408 die("failed to create user data directory");
409409 }
410 free(path_copy);410 // Obtain the next path segment.
411}411 path_segment = strtok_r(NULL, "/", &path_walker);
412412 }
413void setup_user_data() {413
414 const char *user_data = getenv("SNAP_USER_DATA");414 // Close the descriptor for the final directory in the path.
415415 close(fd);
416 // If $SNAP_USER_DATA wasn't defined, check the deprecated416
417 // $SNAP_APP_USER_DATA_PATH.417 free(path_copy);
418 if (user_data == NULL) {418}
419 user_data = getenv("SNAP_APP_USER_DATA_PATH");419
420 // If it's still not defined, there's nothing to do. No need to die,420void setup_user_data()
421 // there's simply no directory to create.421{
422 if (user_data == NULL) {422 const char *user_data = getenv("SNAP_USER_DATA");
423 return;423
424 }424 // If $SNAP_USER_DATA wasn't defined, check the deprecated
425 }425 // $SNAP_APP_USER_DATA_PATH.
426426 if (user_data == NULL) {
427 // Only support absolute paths.427 user_data = getenv("SNAP_APP_USER_DATA_PATH");
428 if (user_data[0] != '/') {428 // If it's still not defined, there's nothing to do. No need to die,
429 die("user data directory must be an absolute path");429 // there's simply no directory to create.
430 }430 if (user_data == NULL) {
431431 return;
432 mkpath(user_data);432 }
433 }
434 // Only support absolute paths.
435 if (user_data[0] != '/') {
436 die("user data directory must be an absolute path");
437 }
438
439 mkpath(user_data);
433}440}
434441
435int main(int argc, char **argv)442int main(int argc, char **argv)
436{443{
437 const int NR_ARGS = 3;444 const int NR_ARGS = 3;
438 if(argc < NR_ARGS+1)445 if (argc < NR_ARGS + 1)
439 die("Usage: %s <appname> <apparmor> <binary>", argv[0]);446 die("Usage: %s <appname> <apparmor> <binary>", argv[0]);
440447
441 const char *appname = argv[1];448 const char *appname = argv[1];
442 const char *aa_profile = argv[2];449 const char *aa_profile = argv[2];
443 const char *binary = argv[3];450 const char *binary = argv[3];
444 unsigned real_uid = getuid();451 unsigned real_uid = getuid();
445 unsigned real_gid = getgid();452 unsigned real_gid = getgid();
446453
447 if(!verify_appname(appname))454 if (!verify_appname(appname))
448 die("appname %s not allowed", appname);455 die("appname %s not allowed", appname);
449456
450 // this code always needs to run as root for the cgroup/udev setup,457 // this code always needs to run as root for the cgroup/udev setup,
451 // however for the tests we allow it to run as non-root458 // however for the tests we allow it to run as non-root
452 if(geteuid() != 0 && getenv("UBUNTU_CORE_LAUNCHER_NO_ROOT") == NULL) {459 if (geteuid() != 0 && getenv("UBUNTU_CORE_LAUNCHER_NO_ROOT") == NULL) {
453 die("need to run as root or suid");460 die("need to run as root or suid");
454 }461 }
455462
456 if(geteuid() == 0) {463 if (geteuid() == 0) {
457464
458 // ensure we run in our own slave mount namespace, this will465 // ensure we run in our own slave mount namespace, this will
459 // create a new mount namespace and make it a slave of "/"466 // create a new mount namespace and make it a slave of "/"
460 //467 //
461 // Note that this means that no mount actions inside our468 // Note that this means that no mount actions inside our
462 // namespace are propagated to the main "/". We need this469 // namespace are propagated to the main "/". We need this
463 // both for the private /tmp we create and for the bind470 // both for the private /tmp we create and for the bind
464 // mounts we do on a classic ubuntu system471 // mounts we do on a classic ubuntu system
465 //472 //
466 // This also means you can't run an automount daemon unter473 // This also means you can't run an automount daemon unter
467 // this launcher474 // this launcher
468 setup_slave_mount_namespace();475 setup_slave_mount_namespace();
469476
470 // do the mounting if run on a non-native snappy system477 // do the mounting if run on a non-native snappy system
471 if(is_running_on_classic_ubuntu()) {478 if (is_running_on_classic_ubuntu()) {
472 setup_snappy_os_mounts();479 setup_snappy_os_mounts();
473 }480 }
474481 // set up private mounts
475 // set up private mounts482 setup_private_mount(appname);
476 setup_private_mount(appname);483
477484 // set up private /dev/pts
478 // set up private /dev/pts485 setup_private_pts();
479 setup_private_pts();486
480487 // this needs to happen as root
481 // this needs to happen as root488 if (snappy_udev_setup_required(appname)) {
482 if(snappy_udev_setup_required(appname)) {489 setup_devices_cgroup(appname);
483 setup_devices_cgroup(appname);490 setup_udev_snappy_assign(appname);
484 setup_udev_snappy_assign(appname);491 }
485 }492 // the rest does not so temporarily drop privs back to calling user
486493 // (we'll permanently drop after loading seccomp)
487 // the rest does not so temporarily drop privs back to calling user494 if (setegid(real_gid) != 0)
488 // (we'll permanently drop after loading seccomp)495 die("setegid failed");
489 if (setegid(real_gid) != 0)496 if (seteuid(real_uid) != 0)
490 die("setegid failed");497 die("seteuid failed");
491 if (seteuid(real_uid) != 0)498
492 die("seteuid failed");499 if (real_gid != 0 && geteuid() == 0)
493500 die("dropping privs did not work");
494 if(real_gid != 0 && geteuid() == 0)501 if (real_uid != 0 && getegid() == 0)
495 die("dropping privs did not work");502 die("dropping privs did not work");
496 if(real_uid != 0 && getegid() == 0)503 }
497 die("dropping privs did not work");504 // Ensure that the user data path exists.
498 }505 setup_user_data();
499506
500 // Ensure that the user data path exists.507 // https://wiki.ubuntu.com/SecurityTeam/Specifications/SnappyConfinement
501 setup_user_data();508
502509 int rc = 0;
503 // https://wiki.ubuntu.com/SecurityTeam/Specifications/SnappyConfinement510 // set apparmor rules
504511 rc = aa_change_onexec(aa_profile);
505 int rc = 0;512 if (rc != 0) {
506 // set apparmor rules513 if (getenv("SNAPPY_LAUNCHER_INSIDE_TESTS") == NULL)
507 rc = aa_change_onexec(aa_profile);514 die("aa_change_onexec failed with %i", rc);
508 if (rc != 0) {515 }
509 if (getenv("SNAPPY_LAUNCHER_INSIDE_TESTS") == NULL)516 // set seccomp
510 die("aa_change_onexec failed with %i", rc);517 rc = seccomp_load_filters(aa_profile);
511 }518 if (rc != 0)
512519 die("seccomp_load_filters failed with %i", rc);
513 // set seccomp520
514 rc = seccomp_load_filters(aa_profile);521 // Permanently drop if not root
515 if (rc != 0)522 if (geteuid() == 0) {
516 die("seccomp_load_filters failed with %i", rc);523 // Note that we do not call setgroups() here because its ok
517524 // that the user keeps the groups he already belongs to
518 // Permanently drop if not root525 if (setgid(real_gid) != 0)
519 if (geteuid() == 0) {526 die("setgid failed");
520 // Note that we do not call setgroups() here because its ok527 if (setuid(real_uid) != 0)
521 // that the user keeps the groups he already belongs to528 die("setuid failed");
522 if (setgid(real_gid) != 0)529
523 die("setgid failed");530 if (real_gid != 0 && (getuid() == 0 || geteuid() == 0))
524 if (setuid(real_uid) != 0)531 die("permanently dropping privs did not work");
525 die("setuid failed");532 if (real_uid != 0 && (getgid() == 0 || getegid() == 0))
526533 die("permanently dropping privs did not work");
527 if(real_gid != 0 && (getuid() == 0 || geteuid() == 0))534 }
528 die("permanently dropping privs did not work");535 // and exec the new binary
529 if(real_uid != 0 && (getgid() == 0 || getegid() == 0))536 argv[NR_ARGS] = (char *)binary,
530 die("permanently dropping privs did not work");537 execv(binary, (char *const *)&argv[NR_ARGS]);
531 }538 perror("execv failed");
532539 return 1;
533 // and exec the new binary
534 argv[NR_ARGS] = (char*)binary,
535 execv(binary, (char *const*)&argv[NR_ARGS]);
536 perror("execv failed");
537 return 1;
538}540}
539541
=== modified file 'src/seccomp.c'
--- src/seccomp.c 2016-03-21 17:22:39 +0000
+++ src/seccomp.c 2016-03-22 12:19:24 +0000
@@ -29,133 +29,140 @@
29char *filter_profile_dir = "/var/lib/snappy/seccomp/profiles/";29char *filter_profile_dir = "/var/lib/snappy/seccomp/profiles/";
3030
31// strip whitespace from the end of the given string (inplace)31// strip whitespace from the end of the given string (inplace)
32size_t trim_right(char *s, size_t slen) {32size_t trim_right(char *s, size_t slen)
33 while(slen > 0 && isspace(s[slen - 1])) {33{
34 s[--slen] = 0;34 while (slen > 0 && isspace(s[slen - 1])) {
35 }35 s[--slen] = 0;
36 return slen;36 }
37 return slen;
37}38}
3839
39int seccomp_load_filters(const char *filter_profile)40int seccomp_load_filters(const char *filter_profile)
40{41{
41 debug("seccomp_load_filters %s", filter_profile);42 debug("seccomp_load_filters %s", filter_profile);
42 int rc = 0;43 int rc = 0;
43 int syscall_nr = -1;44 int syscall_nr = -1;
44 scmp_filter_ctx ctx = NULL;45 scmp_filter_ctx ctx = NULL;
45 FILE *f = NULL;46 FILE *f = NULL;
46 size_t lineno = 0;47 size_t lineno = 0;
4748
48 ctx = seccomp_init(SCMP_ACT_KILL);49 ctx = seccomp_init(SCMP_ACT_KILL);
49 if (ctx == NULL)50 if (ctx == NULL)
50 return ENOMEM;51 return ENOMEM;
5152
52 // Disable NO_NEW_PRIVS because it interferes with exec transitions in53 // Disable NO_NEW_PRIVS because it interferes with exec transitions in
53 // AppArmor. Unfortunately this means that security policies must be very54 // AppArmor. Unfortunately this means that security policies must be very
54 // careful to not allow the following otherwise apps can escape the snadbox:55 // careful to not allow the following otherwise apps can escape the snadbox:
55 // - seccomp syscall56 // - seccomp syscall
56 // - prctl with PR_SET_SECCOMP57 // - prctl with PR_SET_SECCOMP
57 // - ptrace (trace) in AppArmor58 // - ptrace (trace) in AppArmor
58 // - capability sys_admin in AppArmor59 // - capability sys_admin in AppArmor
59 // Note that with NO_NEW_PRIVS disabled, CAP_SYS_ADMIN is required to change60 // Note that with NO_NEW_PRIVS disabled, CAP_SYS_ADMIN is required to change
60 // the seccomp sandbox.61 // the seccomp sandbox.
61 if (getenv("UBUNTU_CORE_LAUNCHER_NO_ROOT") == NULL) {62 if (getenv("UBUNTU_CORE_LAUNCHER_NO_ROOT") == NULL) {
62 rc = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0);63 rc = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0);
63 if (rc != 0) {64 if (rc != 0) {
64 fprintf(stderr, "Cannot disable nnp\n");65 fprintf(stderr, "Cannot disable nnp\n");
65 return -1;66 return -1;
66 }67 }
67 }68 }
6869
69 if (getenv("SNAPPY_LAUNCHER_SECCOMP_PROFILE_DIR") != NULL)70 if (getenv("SNAPPY_LAUNCHER_SECCOMP_PROFILE_DIR") != NULL)
70 filter_profile_dir = getenv("SNAPPY_LAUNCHER_SECCOMP_PROFILE_DIR");71 filter_profile_dir =
7172 getenv("SNAPPY_LAUNCHER_SECCOMP_PROFILE_DIR");
72 char profile_path[128];73
73 if (snprintf(profile_path, sizeof(profile_path), "%s/%s", filter_profile_dir, filter_profile) < 0) {74 char profile_path[128];
74 goto out;75 if (snprintf
75 }76 (profile_path, sizeof(profile_path), "%s/%s", filter_profile_dir,
7677 filter_profile) < 0) {
77 f = fopen(profile_path, "r");78 goto out;
78 if (f == NULL) {79 }
79 fprintf(stderr, "Can not open %s (%s)\n", profile_path, strerror(errno));80
80 return -1;81 f = fopen(profile_path, "r");
81 }82 if (f == NULL) {
82 // 80 characters + '\n' + '\0'83 fprintf(stderr, "Can not open %s (%s)\n", profile_path,
83 char buf[82];84 strerror(errno));
84 while (fgets(buf, sizeof(buf), f) != NULL)85 return -1;
85 {86 }
86 size_t len;87 // 80 characters + '\n' + '\0'
8788 char buf[82];
88 lineno++;89 while (fgets(buf, sizeof(buf), f) != NULL) {
8990 size_t len;
90 // comment, ignore91
91 if(buf[0] == '#')92 lineno++;
92 continue;93
9394 // comment, ignore
94 // ensure the entire line was read95 if (buf[0] == '#')
95 len = strlen(buf);96 continue;
96 if (len == 0)97
97 continue;98 // ensure the entire line was read
98 else if (buf[len - 1] != '\n' && len > (sizeof(buf) - 2)) {99 len = strlen(buf);
99 fprintf(stderr, "seccomp filter line %zu was too long (%zu characters max)\n", lineno, sizeof(buf) - 2);100 if (len == 0)
100 rc = -1;101 continue;
101 goto out;102 else if (buf[len - 1] != '\n' && len > (sizeof(buf) - 2)) {
102 }103 fprintf(stderr,
103104 "seccomp filter line %zu was too long (%zu characters max)\n",
104 // kill final newline105 lineno, sizeof(buf) - 2);
105 len = trim_right(buf, len);106 rc = -1;
106 if (len == 0)107 goto out;
107 continue;108 }
108109 // kill final newline
109 // check for special "@unrestricted" command110 len = trim_right(buf, len);
110 if (strncmp(buf, "@unrestricted", sizeof(buf)) == 0)111 if (len == 0)
111 goto out;112 continue;
112113
113 // syscall not available on this arch/kernel114 // check for special "@unrestricted" command
114 // as this is a syscall whitelist its ok and the error can be ignored115 if (strncmp(buf, "@unrestricted", sizeof(buf)) == 0)
115 syscall_nr = seccomp_syscall_resolve_name(buf);116 goto out;
116 if (syscall_nr == __NR_SCMP_ERROR)117
117 continue;118 // syscall not available on this arch/kernel
118119 // as this is a syscall whitelist its ok and the error can be ignored
119 // a normal line with a syscall120 syscall_nr = seccomp_syscall_resolve_name(buf);
120 rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, syscall_nr, 0);121 if (syscall_nr == __NR_SCMP_ERROR)
121 if (rc != 0) {122 continue;
122 rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall_nr, 0);123
123 if (rc != 0) {124 // a normal line with a syscall
124 fprintf(stderr, "seccomp_rule_add failed with %i for '%s'\n", rc, buf);125 rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, syscall_nr, 0);
125 goto out;126 if (rc != 0) {
126 }127 rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall_nr,
127 }128 0);
128 }129 if (rc != 0) {
129130 fprintf(stderr,
130 // raise privileges to load seccomp policy since we don't have nnp131 "seccomp_rule_add failed with %i for '%s'\n",
131 if (getenv("UBUNTU_CORE_LAUNCHER_NO_ROOT") == NULL) {132 rc, buf);
132 if (seteuid(0) != 0)133 goto out;
133 die("seteuid failed");134 }
134 if (geteuid() != 0)135 }
135 die("raising privs before seccomp_load did not work");136 }
136 }137
137138 // raise privileges to load seccomp policy since we don't have nnp
138 // load it into the kernel139 if (getenv("UBUNTU_CORE_LAUNCHER_NO_ROOT") == NULL) {
139 rc = seccomp_load(ctx);140 if (seteuid(0) != 0)
140141 die("seteuid failed");
141 if (rc != 0) {142 if (geteuid() != 0)
142 fprintf(stderr, "seccomp_load failed with %i\n", rc);143 die("raising privs before seccomp_load did not work");
143 goto out;144 }
144 }145 // load it into the kernel
146 rc = seccomp_load(ctx);
147
148 if (rc != 0) {
149 fprintf(stderr, "seccomp_load failed with %i\n", rc);
150 goto out;
151 }
145152
146 out:153 out:
147 // drop privileges again154 // drop privileges again
148 if (geteuid() == 0) {155 if (geteuid() == 0) {
149 unsigned real_uid = getuid();156 unsigned real_uid = getuid();
150 if (seteuid(real_uid) != 0)157 if (seteuid(real_uid) != 0)
151 die("seteuid failed");158 die("seteuid failed");
152 if (real_uid != 0 && geteuid() == 0)159 if (real_uid != 0 && geteuid() == 0)
153 die("dropping privs after seccomp_load did not work");160 die("dropping privs after seccomp_load did not work");
154 }161 }
155162
156 if (f != NULL) {163 if (f != NULL) {
157 fclose(f);164 fclose(f);
158 }165 }
159 seccomp_release(ctx);166 seccomp_release(ctx);
160 return rc;167 return rc;
161}168}
162169
=== modified file 'src/utils.c'
--- src/utils.c 2015-06-11 10:57:01 +0000
+++ src/utils.c 2016-03-22 12:19:24 +0000
@@ -24,64 +24,66 @@
2424
25void die(const char *msg, ...)25void die(const char *msg, ...)
26{26{
27 va_list va;27 va_list va;
28 va_start(va, msg);28 va_start(va, msg);
29 vfprintf(stderr, msg, va);29 vfprintf(stderr, msg, va);
30 va_end(va);30 va_end(va);
3131
32 if (errno != 0) {32 if (errno != 0) {
33 perror(". errmsg");33 perror(". errmsg");
34 } else {34 } else {
35 fprintf(stderr, "\n");35 fprintf(stderr, "\n");
36 }36 }
37 exit(1);37 exit(1);
38}38}
3939
40bool error(const char *msg, ...)40bool error(const char *msg, ...)
41{41{
42 va_list va;42 va_list va;
43 va_start(va, msg);43 va_start(va, msg);
44 vfprintf(stderr, msg, va);44 vfprintf(stderr, msg, va);
45 va_end(va);45 va_end(va);
4646
47 return false;47 return false;
48}48}
4949
50void debug(const char *msg, ...)50void debug(const char *msg, ...)
51{51{
52 if(getenv("UBUNTU_CORE_LAUNCHER_DEBUG") == NULL)52 if (getenv("UBUNTU_CORE_LAUNCHER_DEBUG") == NULL)
53 return;53 return;
5454
55 va_list va;55 va_list va;
56 va_start(va, msg);56 va_start(va, msg);
57 fprintf(stderr, "DEBUG: ");57 fprintf(stderr, "DEBUG: ");
58 vfprintf(stderr, msg, va);58 vfprintf(stderr, msg, va);
59 fprintf(stderr, "\n");59 fprintf(stderr, "\n");
60 va_end(va);60 va_end(va);
61}61}
6262
63void write_string_to_file(const char *filepath, const char *buf) {63void write_string_to_file(const char *filepath, const char *buf)
64 debug("write_string_to_file %s %s", filepath, buf);64{
65 FILE *f = fopen(filepath, "w");65 debug("write_string_to_file %s %s", filepath, buf);
66 if (f == NULL)66 FILE *f = fopen(filepath, "w");
67 die("fopen %s failed", filepath);67 if (f == NULL)
68 if (fwrite(buf, strlen(buf), 1, f) != 1)68 die("fopen %s failed", filepath);
69 die("fwrite failed");69 if (fwrite(buf, strlen(buf), 1, f) != 1)
70 if (fflush(f) != 0)70 die("fwrite failed");
71 die("fflush failed");71 if (fflush(f) != 0)
72 fclose(f);72 die("fflush failed");
73}73 fclose(f);
7474}
75int must_snprintf(char *str, size_t size, const char *format, ...) {75
76 int n = -1;76int must_snprintf(char *str, size_t size, const char *format, ...)
7777{
78 va_list va;78 int n = -1;
79 va_start(va, format);79
80 n = vsnprintf(str, size, format, va);80 va_list va;
81 va_end(va);81 va_start(va, format);
8282 n = vsnprintf(str, size, format, va);
83 if(n < 0 || n >= size)83 va_end(va);
84 die("failed to snprintf %s", str);84
8585 if (n < 0 || n >= size)
86 return n;86 die("failed to snprintf %s", str);
87
88 return n;
87}89}
8890
=== modified file 'src/utils.h'
--- src/utils.h 2015-05-20 11:10:29 +0000
+++ src/utils.h 2016-03-22 12:19:24 +0000
@@ -20,19 +20,19 @@
20#define CORE_LAUNCHER_UTILS_H20#define CORE_LAUNCHER_UTILS_H
2121
22__attribute__ ((noreturn))22__attribute__ ((noreturn))
23__attribute__ ((format (printf, 1, 2)))23 __attribute__ ((format(printf, 1, 2)))
24void die(const char *fmt, ...);24void die(const char *fmt, ...);
2525
26__attribute__ ((format (printf, 1, 2)))26__attribute__ ((format(printf, 1, 2)))
27bool error(const char *fmt, ...);27bool error(const char *fmt, ...);
2828
29__attribute__ ((format (printf, 1, 2)))29__attribute__ ((format(printf, 1, 2)))
30void debug(const char *fmt, ...);30void debug(const char *fmt, ...);
3131
32void write_string_to_file(const char *filepath, const char *buf);32void write_string_to_file(const char *filepath, const char *buf);
3333
34// snprintf version that dies on any error condition34// snprintf version that dies on any error condition
35__attribute__ ((format (printf, 3, 4)))35__attribute__ ((format(printf, 3, 4)))
36int must_snprintf(char *str, size_t size, const char *format, ...);36int must_snprintf(char *str, size_t size, const char *format, ...);
3737
38#endif38#endif

Subscribers

People subscribed via source and target branches