3
* Copyright © 2013 Stphane Graber
4
* Author: Stphane Graber <stgraber@ubuntu.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2, as
8
* published by the Free Software Foundation.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License along
16
* with this program; if not, write to the Free Software Foundation, Inc.,
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
DBusConnection *server_conn;
24
bool master_running(void)
28
/* is manager already running under cgmanager.lower */
29
server_conn = nih_dbus_connect(CGPROXY_DBUS_PATH, NULL);
31
dbus_connection_unref (server_conn);
34
err = nih_error_get();
37
/* is manager running under cgmanager */
38
server_conn = nih_dbus_connect(CGMANAGER_DBUS_PATH, NULL);
40
dbus_connection_unref (server_conn);
43
err = nih_error_get();
50
bool exists_upper = false, exists_lower = false;
54
* If /sys/fs/cgroup/cgmanager.lower exists,
55
* if /sys/fs/cgroup/cgmanager exists, then exit (proxy already running)
56
* start up, connect to .lower
58
* if /sys/fs/cgroup/cgmanager exists, move it to /sys/fs/cgroup/cgmanager.lower
59
* start up and connect to .lower
61
server_conn = nih_dbus_connect(CGMANAGER_DBUS_PATH, NULL);
64
dbus_connection_unref (server_conn);
66
err = nih_error_get();
69
server_conn = nih_dbus_connect(CGPROXY_DBUS_PATH, NULL);
73
err = nih_error_get();
76
if (exists_upper && exists_lower) {
77
dbus_connection_unref (server_conn);
78
nih_fatal("proxy already running");
79
return -1; // proxy already running
82
// we've got the sock we need, all set.
85
//move /sys/fs/cgroup/cgmanager to /sys/fs/cgroup/cgmanager.lower
86
if (mkdir(CGPROXY_DIR, 0755) < 0 && errno != EEXIST) {
87
nih_fatal("failed to create lower sock");
90
if (mount(CGMANAGER_DIR, CGPROXY_DIR, "none", MS_MOVE, 0) < 0) {
91
/* it wasn't a mount, meaning we are at the host
92
* level on an old kernel. So rename it */
93
if (unlink(CGPROXY_SOCK) && errno != ENOENT)
94
nih_warn("failed to remove %s: %s", CGPROXY_SOCK,
96
if (rmdir(CGPROXY_DIR) && errno != ENOENT)
97
nih_warn("failed to remove %s: %s", CGPROXY_DIR,
99
if (rename(CGMANAGER_DIR, CGPROXY_DIR) < 0) {
100
nih_fatal("unable to rename the socket");
103
if (mkdir(CGMANAGER_DIR, 0755) < 0) {
104
nih_fatal("unable to create socket dir");
109
server_conn = nih_dbus_connect(CGPROXY_DBUS_PATH, NULL);
111
err = nih_error_get();
112
nih_fatal("Failed to open connection to %s: %s",
113
CGPROXY_DBUS_PATH, err->message);
119
static int checkmaster = FALSE;
121
bool send_dummy_msg(DBusConnection *conn)
123
DBusMessage *message = NULL;
124
DBusMessageIter iter;
126
message = dbus_message_new_method_call(dbus_bus_get_unique_name(conn),
127
"/org/linuxcontainers/cgmanager",
128
"org.linuxcontainers.cgmanager0_0", "Ping");
129
dbus_message_set_no_reply(message, TRUE);
130
dbus_message_iter_init_append(message, &iter);
131
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &a)) {
132
nih_error("%s: out of memory", __func__);
135
dbus_connection_send(conn, message, NULL);
136
dbus_connection_flush(conn);
137
dbus_message_unref(message);
141
static DBusMessage *start_dbus_request(const char *method, int *sv)
145
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
146
nih_error("%s: Error creating socketpair: %s",
147
__func__, strerror(errno));
150
if (setsockopt(sv[1], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
151
nih_error("%s: setsockopt: %s", __func__, strerror(errno));
154
if (setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
155
nih_error("%s: setsockopt: %s", __func__, strerror(errno));
159
return dbus_message_new_method_call(dbus_bus_get_unique_name(server_conn),
160
"/org/linuxcontainers/cgmanager",
161
"org.linuxcontainers.cgmanager0_0", method);
168
static bool complete_dbus_request(DBusMessage *message,
169
int *sv, struct ucred *rcred, struct ucred *vcred)
173
if (!dbus_connection_send(server_conn, message, NULL)) {
174
nih_error("%s: failed to send dbus message", __func__);
175
dbus_message_unref(message);
178
dbus_connection_flush(server_conn);
179
dbus_message_unref(message);
181
if (recv(sv[0], buf, 1, 0) != 1) {
182
nih_error("%s: Error getting reply from server over socketpair",
186
if (send_creds(sv[0], rcred)) {
187
nih_error("%s: Error sending pid over SCM_CREDENTIAL",
192
if (!vcred) // this request only requires one scm_credential
195
if (recv(sv[0], buf, 1, 0) != 1) {
196
nih_error("%s: Error getting reply from server over socketpair",
200
if (send_creds(sv[0], vcred)) {
201
nih_error("%s: Error sending pid over SCM_CREDENTIAL",
209
int get_pid_cgroup_main (void *parent, const char *controller,
210
struct ucred p, struct ucred r, struct ucred v, char **output)
212
DBusMessage *message;
213
DBusMessageIter iter;
215
char s[MAXPATHLEN] = { 0 };
217
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
218
nih_error("%s: proxy != requestor", __func__);
222
if (!(message = start_dbus_request("GetPidCgroupScm", sv))) {
223
nih_error("%s: error starting dbus request", __func__);
227
dbus_message_iter_init_append(message, &iter);
228
if (!dbus_message_iter_append_basic (&iter,
231
nih_error("%s: out of memory", __func__);
234
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
235
nih_error("%s: out of memory", __func__);
239
if (!complete_dbus_request(message, sv, &r, &v)) {
240
nih_error("%s: error completing dbus request", __func__);
244
// TODO - switch to nih_io_message_recv?
245
if (recv(sv[0], s, MAXPATHLEN-1, 0) <= 0)
246
nih_error("%s: Error reading result from cgmanager",
249
*output = NIH_MUST( nih_strdup(parent, s) );
258
int do_move_pid_main (const char *controller, const char *cgroup,
259
struct ucred p, struct ucred r, struct ucred v,
262
DBusMessage *message;
263
DBusMessageIter iter;
267
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
268
nih_error("%s: proxy != requestor", __func__);
272
if (!sane_cgroup(cgroup)) {
273
nih_error("unsafe cgroup");
277
if (!(message = start_dbus_request(cmd, sv))) {
278
nih_error("%s: error starting dbus request", __func__);
282
dbus_message_iter_init_append(message, &iter);
283
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
285
nih_error("%s: out of memory", __func__);
288
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
289
nih_error("%s: out of memory", __func__);
292
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
293
nih_error("%s: out of memory", __func__);
297
if (!complete_dbus_request(message, sv, &r, &v)) {
298
nih_error("%s: error completing dbus request", __func__);
302
if (recv(sv[0], buf, 1, 0) == 1 && *buf == '1')
310
int move_pid_main (const char *controller, const char *cgroup,
311
struct ucred p, struct ucred r, struct ucred v)
313
if (!sane_cgroup(cgroup)) {
314
nih_error("unsafe cgroup");
317
if (cgroup[0] == '/') {
318
nih_error("uid %u tried to escape its cgroup", r.uid);
322
return do_move_pid_main(controller, cgroup, p, r, v, "MovePidScm");
325
int move_pid_abs_main (const char *controller, const char *cgroup,
326
struct ucred p, struct ucred r, struct ucred v)
329
nih_error("uid %u tried to escape", r.uid);
332
if (!sane_cgroup(cgroup)) {
333
nih_error("unsafe cgroup");
336
return do_move_pid_main(controller, cgroup, p, r, v, "MovePidAbsScm");
339
int create_main (const char *controller, const char *cgroup, struct ucred p,
340
struct ucred r, int32_t *existed)
342
DBusMessage *message;
343
DBusMessageIter iter;
347
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
348
nih_error("%s: proxy != requestor", __func__);
352
if (!sane_cgroup(cgroup)) {
353
nih_error("unsafe cgroup");
357
if (!(message = start_dbus_request("CreateScm", sv))) {
358
nih_error("%s: error starting dbus request", __func__);
362
dbus_message_iter_init_append(message, &iter);
363
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
364
nih_error("%s: out of memory", __func__);
367
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
368
nih_error("%s: out of memory", __func__);
371
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
372
nih_error("%s: out of memory", __func__);
376
if (!complete_dbus_request(message, sv, &r, NULL)) {
377
nih_error("%s: error completing dbus request", __func__);
381
if (recv(sv[0], buf, 1, 0) == 1 && (*buf == '1' || *buf == '2'))
383
*existed = *buf == '2' ? 1 : -1;
390
int chown_main (const char *controller, const char *cgroup,
391
struct ucred p, struct ucred r, struct ucred v)
393
DBusMessage *message;
394
DBusMessageIter iter;
398
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
399
nih_error("%s: proxy != requestor", __func__);
403
if (!sane_cgroup(cgroup)) {
404
nih_error("unsafe cgroup");
408
if (!(message = start_dbus_request("ChownScm", sv))) {
409
nih_error("%s: error starting dbus request", __func__);
413
dbus_message_iter_init_append(message, &iter);
414
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
415
nih_error("%s: out of memory", __func__);
418
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
419
nih_error("%s: out of memory", __func__);
422
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
423
nih_error("%s: out of memory", __func__);
427
if (!complete_dbus_request(message, sv, &r, &v)) {
428
nih_error("%s: error completing dbus request", __func__);
432
if (recv(sv[0], buf, 1, 0) == 1 && *buf == '1')
440
int chmod_main (const char *controller, const char *cgroup, const char *file,
441
struct ucred p, struct ucred r, int mode)
443
DBusMessage *message;
444
DBusMessageIter iter;
448
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
449
nih_error("%s: proxy != requestor", __func__);
453
if (!sane_cgroup(cgroup)) {
454
nih_error("unsafe cgroup");
458
if (!(message = start_dbus_request("ChmodScm", sv))) {
459
nih_error("%s: error starting dbus request", __func__);
463
dbus_message_iter_init_append(message, &iter);
464
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
465
nih_error("%s: out of memory", __func__);
468
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
469
nih_error("%s: out of memory", __func__);
472
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &file)) {
473
nih_error("%s: out of memory", __func__);
476
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &mode)) {
477
nih_error("%s: out of memory", __func__);
480
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
481
nih_error("%s: out of memory", __func__);
485
if (!complete_dbus_request(message, sv, &r, NULL)) {
486
nih_error("%s: error completing dbus request", __func__);
490
if (recv(sv[0], buf, 1, 0) == 1 && *buf == '1')
498
int get_value_main (void *parent, const char *controller, const char *cgroup,
499
const char *key, struct ucred p, struct ucred r, char **value)
501
DBusMessage *message;
502
DBusMessageIter iter;
504
char output[MAXPATHLEN] = { 0 };
506
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
507
nih_error("%s: proxy != requestor", __func__);
511
if (!sane_cgroup(cgroup)) {
512
nih_error("unsafe cgroup");
516
if (!(message = start_dbus_request("GetValueScm", sv))) {
517
nih_error("%s: error starting dbus request", __func__);
521
dbus_message_iter_init_append(message, &iter);
522
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
523
nih_error("%s: out of memory", __func__);
526
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
527
nih_error("%s: out of memory", __func__);
530
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key)) {
531
nih_error("%s: out of memory", __func__);
534
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
535
nih_error("%s: out of memory", __func__);
539
if (!complete_dbus_request(message, sv, &r, NULL)) {
540
nih_error("%s: error completing dbus request", __func__);
544
if (recv(sv[0], output, MAXPATHLEN, 0) <= 0) {
545
nih_error("%s: Failed reading string from cgmanager: %s",
546
__func__, strerror(errno));
548
*value = NIH_MUST( nih_strdup(parent, output) );
557
int set_value_main (const char *controller, const char *cgroup,
558
const char *key, const char *value, struct ucred p,
561
DBusMessage *message;
562
DBusMessageIter iter;
566
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
567
nih_error("%s: proxy != requestor", __func__);
571
if (!sane_cgroup(cgroup)) {
572
nih_error("unsafe cgroup");
576
if (!(message = start_dbus_request("SetValueScm", sv))) {
577
nih_error("%s: error starting dbus request", __func__);
581
dbus_message_iter_init_append(message, &iter);
582
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
583
nih_error("%s: out of memory", __func__);
586
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
587
nih_error("%s: out of memory", __func__);
590
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key)) {
591
nih_error("%s: out of memory", __func__);
594
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value)) {
595
nih_error("%s: out of memory", __func__);
598
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
599
nih_error("%s: out of memory", __func__);
603
if (!complete_dbus_request(message, sv, &r, NULL)) {
604
nih_error("%s: error completing dbus request", __func__);
608
if (recv(sv[0], buf, 1, 0) == 1 && *buf == '1')
616
int remove_main (const char *controller, const char *cgroup, struct ucred p,
617
struct ucred r, int recursive, int32_t *existed)
619
DBusMessage *message;
620
DBusMessageIter iter;
624
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
625
nih_error("%s: proxy != requestor", __func__);
629
if (!sane_cgroup(cgroup)) {
630
nih_error("unsafe cgroup");
634
if (!(message = start_dbus_request("RemoveScm", sv))) {
635
nih_error("%s: error starting dbus request", __func__);
639
dbus_message_iter_init_append(message, &iter);
640
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
641
nih_error("%s: out of memory", __func__);
644
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
645
nih_error("%s: out of memory", __func__);
648
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &recursive)) {
649
nih_error("%s: out of memory", __func__);
652
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
653
nih_error("%s: out of memory", __func__);
657
if (!complete_dbus_request(message, sv, &r, NULL)) {
658
nih_error("%s: error completing dbus request", __func__);
662
if (recv(sv[0], buf, 1, 0) == 1 && (*buf == '1' || *buf == '2'))
664
*existed = *buf == '2' ? 1 : -1;
671
int get_tasks_main (void *parent, const char *controller, const char *cgroup,
672
struct ucred p, struct ucred r, int32_t **pids)
674
DBusMessage *message;
675
DBusMessageIter iter;
681
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
682
nih_error("%s: proxy != requestor", __func__);
686
if (!sane_cgroup(cgroup)) {
687
nih_error("unsafe cgroup");
691
if (!(message = start_dbus_request("GetTasksScm", sv))) {
692
nih_error("%s: error starting dbus request", __func__);
696
dbus_message_iter_init_append(message, &iter);
697
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
698
nih_error("%s: out of memory", __func__);
701
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
702
nih_error("%s: out of memory", __func__);
705
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
706
nih_error("%s: out of memory", __func__);
710
if (!complete_dbus_request(message, sv, &r, NULL)) {
711
nih_error("%s: error completing dbus request", __func__);
714
if (recv(sv[0], &nrpids, sizeof(uint32_t), 0) != sizeof(uint32_t))
721
*pids = NIH_MUST( nih_alloc(parent, nrpids * sizeof(uint32_t)) );
722
for (i=0; i<nrpids; i++) {
723
get_scm_creds_sync(sv[0], &tcred);
724
if (tcred.pid == -1) {
725
nih_error("%s: Failed getting pid from server",
729
(*pids)[i] = tcred.pid;
738
int list_children_main (void *parent, const char *controller, const char *cgroup,
739
struct ucred p, struct ucred r, char ***output)
741
DBusMessage *message;
742
DBusMessageIter iter;
746
nih_local char * paths = NULL;
751
if (memcmp(&p, &r, sizeof(struct ucred)) != 0) {
752
nih_error("%s: proxy != requestor", __func__);
756
if (!sane_cgroup(cgroup)) {
757
nih_error("unsafe cgroup");
761
if (!(message = start_dbus_request("ListChildrenScm", sv))) {
762
nih_error("%s: error starting dbus request", __func__);
766
dbus_message_iter_init_append(message, &iter);
767
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
768
nih_error("%s: out of memory", __func__);
771
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
772
nih_error("%s: out of memory", __func__);
775
if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
776
nih_error("%s: out of memory", __func__);
780
if (!complete_dbus_request(message, sv, &r, NULL)) {
781
nih_error("%s: error completing dbus request", __func__);
785
if (recv(sv[0], &nrkids, sizeof(int32_t), 0) != sizeof(int32_t))
792
nih_error("Server encountered an error: bad cgroup?");
796
if (recv(sv[0], &len, sizeof(uint32_t), 0) != sizeof(uint32_t))
799
paths = nih_alloc(NULL, len);
800
if (read(sv[0], paths, len) != len) {
801
nih_error("%s: Failed getting paths from server", __func__);
805
*output = NIH_MUST( nih_alloc(parent, sizeof( char*)*(nrkids+1)) );
808
(*output)[nrkids] = NULL;
809
for (i=0; i<nrkids; i++) {
810
(*output)[i] = NIH_MUST( nih_strdup(parent, s) );
823
* Command-line options accepted by this program.
825
static NihOption options[] = {
826
{ 0, "daemon", N_("Detach and run in the background"),
827
NULL, NULL, &daemonise, NULL },
828
{ 0, "check-master", N_("Check whether cgmanager is running"),
829
NULL, NULL, &checkmaster, NULL },
835
main (int argc, char *argv[])
842
nih_main_init (argv[0]);
844
nih_option_set_synopsis (_("Control group proxy"));
845
nih_option_set_help (_("The cgroup manager proxy"));
847
args = nih_option_parser (NULL, argc, argv, options, FALSE);
851
if (geteuid() != 0) {
852
nih_error(_("Cgmanager proxy must be run as root"));
857
* If we are called with checkmaster, then only check whether
858
* cgmanager is running. This is used by the init script to
859
* determine whether to run cgmanager or cgproxy
862
if (master_running())
866
if (setup_proxy() < 0) {
867
nih_fatal ("Failed to set up as proxy");
871
/* Setup the DBus server */
872
server = nih_dbus_server ( CGMANAGER_DBUS_PATH, client_connect,
874
nih_assert (server != NULL);
876
if (stat("/proc/self/ns/pid", &sb) == 0) {
877
mypidns = read_pid_ns_link(getpid());
878
setns_pid_supported = true;
881
if (stat("/proc/self/ns/user", &sb) == 0) {
882
myuserns = read_user_ns_link(getpid());
883
setns_user_supported = true;
888
if (nih_main_daemonise () < 0) {
891
err = nih_error_get ();
892
nih_fatal ("%s: %s", _("Unable to become daemon"),
901
* We have to send a message to force fd passing over the dbus
902
* link to be negotiated. Else when we try to attach an fd we'll
905
if (!send_dummy_msg(server_conn)) {
906
nih_fatal("Failed to send opening ping to cgmanager");
910
ret = nih_main_loop ();
912
/* Destroy any PID file we may have created */
914
nih_main_unlink_pidfile();