Merge lp:~jamesodhunt/upstart/bug-1083723 into lp:~upstart-devel/upstart/1.6

Proposed by James Hunt
Status: Merged
Merged at revision: 1393
Proposed branch: lp:~jamesodhunt/upstart/bug-1083723
Merge into: lp:~upstart-devel/upstart/1.6
Diff against target: 258 lines (+160/-6)
6 files modified
dbus/com.ubuntu.Upstart.xml (+2/-0)
init/control.c (+55/-0)
init/control.h (+3/-0)
util/Makefile.am (+2/-1)
util/man/telinit.8 (+7/-1)
util/telinit.c (+91/-4)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/bug-1083723
Reviewer Review Type Date Requested Status
Steve Langasek Needs Fixing
Review via email: mp+137898@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Steve Langasek (vorlon) wrote :

+ /* Disallow users from restarting Upstart, unless they happen to
+ * own this process (which they may do in the test scenario and
+ * when running Upstart as a non-privileged user).
+ */
+ if (session && session->user && session->user != uid) {

Same comment as for https://code.launchpad.net/~jamesodhunt/upstart/bug-1079715/+merge/135388: this should be 'session && session->user != uid', and not assume that all users should be allowed to call this method for a non-null session with user==0.

+ if (init_is_upstart ()) {
+ ret = restart_upstart ();
+ }

Please get rid of the init_is_upstart() check (and function); now that restarting is done over dbus, we shouldn't open a separate connection first to check that init is upstart. I think it's reasonable and appropriate that if someone calls 'telinit u' against a non-upstart init, and as a result init does not re-exec itself, telinit should exit non-zero instead of silently failing to take the requested action. Note that this is not an issue for the library upgrade case, because the library packages sensibly do:

 telinit u 2>/dev/null || true

If there is some reason I'm missing that it's important to return 0 in the case of a non-upstart init, please at least don't call upstart_open() twice, but instead save the result so we're not setting up and tearing down the dbus connection twice.

Otherwise, this looks good.

review: Needs Fixing
lp:~jamesodhunt/upstart/bug-1083723 updated
1396. By James Hunt

* init/control.c: control_restart():
  - Simplified session check.
* util/telinit.c:
  - init_is_upstart(): Removed as redundant.
  - upstart_open(): Removed erroneous comment.
  - restart_upstart(): Changed return values for consistency with other
    calls in main() where an error is expected to set ret to < 0.
  - main(): Just call restart_upstart() in re-exec scenario to avoid the
    creation of a second D-Bus connection.

Revision history for this message
James Hunt (jamesodhunt) wrote :

> + /* Disallow users from restarting Upstart, unless they happen to
> + * own this process (which they may do in the test scenario and
> + * when running Upstart as a non-privileged user).
> + */
> + if (session && session->user && session->user != uid) {
>
> Same comment as for https://code.launchpad.net/~jamesodhunt/upstart/bug-1079715/+merge/135388: this should be 'session && session->user != uid', and not assume that all users should be allowed to call this method for a non-null session with user==0.

Fixed.

>
> + if (init_is_upstart ()) {
> + ret = restart_upstart ();
> + }
>
> Please get rid of the init_is_upstart() check (and function); now that restarting is done over dbus, we shouldn't open a separate connection first to check that init is upstart. I think it's reasonable and appropriate that if someone calls 'telinit u' against a non-upstart init, and as a result init does not re-exec itself, telinit should exit non-zero instead of silently failing to take the requested action. Note that this is not an issue for the library upgrade case, because the library packages sensibly do:
>
> telinit u 2>/dev/null || true
>
> If there is some reason I'm missing that it's important to return 0 in the case of a non-upstart init, please at least don't call upstart_open() twice, but instead save the result so we're not setting up and tearing down the dbus connection twice.

The initial init_is_upstart() check would have given us the opportunity to display a cleaner error message in the non-Upstart init scenario without more invasive code changes (something along the lines of "telinit: ERROR - init is not Upstart"). What currently happens if /sbin/init is not Upstart is this:

    # telinit u
    telinit: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory
    # echo $?
    1

It's not particularly pretty, but we don't anticipate this scenario happening much and of course it can be quietened down by redirecting stderr if required.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'dbus/com.ubuntu.Upstart.xml'
--- dbus/com.ubuntu.Upstart.xml 2012-09-09 21:22:06 +0000
+++ dbus/com.ubuntu.Upstart.xml 2012-12-06 11:40:27 +0000
@@ -34,6 +34,8 @@
34 <arg name="jobs" type="ao" direction="out" />34 <arg name="jobs" type="ao" direction="out" />
35 </method>35 </method>
3636
37 <method name="Restart"/>
38
37 <!-- Signals for changes to the job list -->39 <!-- Signals for changes to the job list -->
38 <signal name="JobAdded">40 <signal name="JobAdded">
39 <arg name="job" type="o" />41 <arg name="job" type="o" />
4042
=== modified file 'init/control.c'
--- init/control.c 2012-09-20 15:16:52 +0000
+++ init/control.c 2012-12-06 11:40:27 +0000
@@ -949,3 +949,58 @@
949949
950 return 0;950 return 0;
951}951}
952
953/**
954 * control_restart:
955 * @data: not used,
956 * @message: D-Bus connection and message received.
957 *
958 * Implements the Restart method of the com.ubuntu.Upstart
959 * interface.
960 *
961 * Called to request that Upstart performs a stateful re-exec.
962 *
963 * Returns: zero on success, negative value on raised error.
964 **/
965int
966control_restart (void *data,
967 NihDBusMessage *message)
968{
969 Session *session;
970 uid_t uid;
971
972 nih_assert (message != NULL);
973
974 uid = getuid ();
975
976 /* Get the relevant session */
977 session = session_from_dbus (NULL, message);
978
979 /* Chroot sessions must not be able to influence
980 * the outside system.
981 *
982 * Making this a NOP is safe since it is the Upstart outside the
983 * chroot which manages all chroot jobs.
984 */
985 if (session && session->chroot) {
986 nih_warn (_("Ignoring restart request from chroot session"));
987 return 0;
988 }
989
990 /* Disallow users from restarting Upstart, unless they happen to
991 * own this process (which they may do in the test scenario and
992 * when running Upstart as a non-privileged user).
993 */
994 if (session && session->user != uid) {
995 nih_dbus_error_raise_printf (
996 DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
997 _("You do not have permission to request restart"));
998 return -1;
999 }
1000
1001 nih_info (_("Restarting"));
1002
1003 stateful_reexec ();
1004
1005 return 0;
1006}
9521007
=== modified file 'init/control.h'
--- init/control.h 2012-09-11 14:59:40 +0000
+++ init/control.h 2012-12-06 11:40:27 +0000
@@ -105,6 +105,9 @@
105int control_bus_release_name (void)105int control_bus_release_name (void)
106 __attribute__ ((warn_unused_result));106 __attribute__ ((warn_unused_result));
107107
108int control_restart (void *data, NihDBusMessage *message)
109 __attribute__ ((warn_unused_result));
110
108NIH_END_EXTERN111NIH_END_EXTERN
109112
110#endif /* INIT_CONTROL_H */113#endif /* INIT_CONTROL_H */
111114
=== modified file 'util/Makefile.am'
--- util/Makefile.am 2011-06-01 11:13:42 +0000
+++ util/Makefile.am 2012-12-06 11:40:27 +0000
@@ -71,7 +71,8 @@
71 utmp.c utmp.h \71 utmp.c utmp.h \
72 sysv.c sysv.h72 sysv.c sysv.h
73nodist_telinit_SOURCES = \73nodist_telinit_SOURCES = \
74 $(com_ubuntu_Upstart_OUTPUTS)74 $(com_ubuntu_Upstart_OUTPUTS) \
75 $(com_ubuntu_Upstart_Instance_OUTPUTS)
75telinit_LDADD = \76telinit_LDADD = \
76 $(LTLIBINTL) \77 $(LTLIBINTL) \
77 $(NIH_LIBS) \78 $(NIH_LIBS) \
7879
=== modified file 'util/man/telinit.8'
--- util/man/telinit.8 2012-11-07 14:28:34 +0000
+++ util/man/telinit.8 2012-12-06 11:40:27 +0000
@@ -71,10 +71,16 @@
71.BR U " or " u71.BR U " or " u
72to request that the72to request that the
73.BR init (8)73.BR init (8)
74daemon re-execute itself. This is necessary when upgrading the74daemon re-execute itself. This is necessary when upgrading the Upstart
75.BR init (8)75.BR init (8)
76daemon itself or any of its dependent system libraries76daemon itself or any of its dependent system libraries
77to ensure disks can be unmounted cleanly on shutdown.77to ensure disks can be unmounted cleanly on shutdown.
78
79Note that if the init daemon is
80.I not
81Upstart, this option will have no effect on the running
82.BR init (8)
83daemon.
78.\"84.\"
79.SH OPTIONS85.SH OPTIONS
80.TP86.TP
8187
=== modified file 'util/telinit.c'
--- util/telinit.c 2009-07-09 11:50:19 +0000
+++ util/telinit.c 2012-12-06 11:40:27 +0000
@@ -38,12 +38,27 @@
38#include <nih/logging.h>38#include <nih/logging.h>
39#include <nih/error.h>39#include <nih/error.h>
4040
41#include <nih-dbus/dbus_error.h>
42#include <nih-dbus/dbus_proxy.h>
43#include <nih-dbus/errors.h>
44#include <nih-dbus/dbus_connection.h>
45
46#include "dbus/upstart.h"
47
48#include "com.ubuntu.Upstart.h"
49
41#include "sysv.h"50#include "sysv.h"
4251
4352
44/* Prototypes for option functions */53/* Prototypes for option functions */
45int env_option (NihOption *option, const char *arg);54int env_option (NihOption *option, const char *arg);
4655
56NihDBusProxy * upstart_open (const void *parent)
57 __attribute__ ((warn_unused_result));
58
59int restart_upstart (void)
60 __attribute__ ((warn_unused_result));
61
4762
48/**63/**
49 * extra_env:64 * extra_env:
@@ -83,6 +98,79 @@
83 return 0;98 return 0;
84}99}
85100
101/**
102 * upstart_open:
103 * @parent: parent object for new proxy.
104 *
105 * Opens a connection to the Upstart init daemon and returns a proxy
106 * to the manager object. If @dest_name is not NULL, a connection is
107 * instead opened to the system bus and the proxy linked to the
108 * well-known name given.
109 *
110 * If @parent is not NULL, it should be a pointer to another object
111 * which will be used as a parent for the returned proxy. When all
112 * parents of the returned proxy are freed, the returned proxy will
113 * also be freed.
114 *
115 * Returns: newly allocated D-Bus proxy or NULL on raised error.
116 **/
117NihDBusProxy *
118upstart_open (const void *parent)
119{
120 DBusError dbus_error;
121 DBusConnection *connection;
122 NihDBusProxy * upstart;
123
124 dbus_error_init (&dbus_error);
125
126 connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
127 if (! connection) {
128 nih_dbus_error_raise (dbus_error.name, dbus_error.message);
129 dbus_error_free (&dbus_error);
130 return NULL;
131 }
132
133 dbus_connection_set_exit_on_disconnect (connection, FALSE);
134 dbus_error_free (&dbus_error);
135
136 upstart = nih_dbus_proxy_new (parent, connection,
137 DBUS_SERVICE_UPSTART,
138 DBUS_PATH_UPSTART,
139 NULL, NULL);
140 if (! upstart) {
141 dbus_connection_unref (connection);
142 return NULL;
143 }
144
145 upstart->auto_start = FALSE;
146
147 /* Drop initial reference now the proxy holds one */
148 dbus_connection_unref (connection);
149
150 return upstart;
151}
152
153/**
154 * restart_upstart:
155 *
156 * Request Upstart restart itself.
157 *
158 * Returns: 0 on SUCCESS, -1 on raised error.
159 **/
160int
161restart_upstart (void)
162{
163 nih_local NihDBusProxy *upstart = NULL;
164
165 upstart = upstart_open (NULL);
166 if (! upstart)
167 return -1;
168
169 if (upstart_restart_sync (NULL, upstart) < 0)
170 return -1;
171
172 return 0;
173}
86174
87#ifndef TEST175#ifndef TEST
88/**176/**
@@ -107,7 +195,7 @@
107{195{
108 char **args;196 char **args;
109 int runlevel;197 int runlevel;
110 int ret;198 int ret = 0;
111199
112 nih_main_init (argv[0]);200 nih_main_init (argv[0]);
113201
@@ -174,9 +262,8 @@
174 break;262 break;
175 case 'U':263 case 'U':
176 case 'u':264 case 'u':
177 ret = kill (1, SIGTERM);265 /* If /sbin/init is not Upstart, just exit non-zero */
178 if (ret < 0)266 ret = restart_upstart ();
179 nih_error_raise_system ();
180 break;267 break;
181 default:268 default:
182 nih_assert_not_reached ();269 nih_assert_not_reached ();

Subscribers

People subscribed via source and target branches

to all changes: