Merge lp:~broder/upstart/drop-privileges into lp:upstart

Proposed by Evan Broder
Status: Merged
Merged at revision: 1331
Proposed branch: lp:~broder/upstart/drop-privileges
Merge into: lp:upstart
Diff against target: 748 lines (+536/-8)
12 files modified
contrib/vim/syntax/upstart.vim (+1/-1)
init/errors.h (+4/-0)
init/job_class.c (+3/-0)
init/job_class.h (+4/-0)
init/job_process.c (+82/-0)
init/job_process.h (+4/-0)
init/man/init.5 (+26/-0)
init/parse_job.c (+84/-0)
init/tests/test_job_class.c (+4/-0)
init/tests/test_job_process.c (+49/-7)
init/tests/test_parse_job.c (+234/-0)
util/tests/test_user_sessions.sh (+41/-0)
To merge this branch: bzr merge lp:~broder/upstart/drop-privileges
Reviewer Review Type Date Requested Status
James Hunt Needs Fixing
Review via email: mp+81417@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Hunt (jamesodhunt) wrote :

* init/man/init.5:

- Typo 'unspceified'.
- To avoid any confusion, I think it's worth explaining that system jobs which specify "setuid X"
cannot be controlled by user X since they are not user jobs: they are simply jobs running as the
user in question [*].

* init/job_process.c:job_process_spawn():

- That fchown() looks potentially unsafe:

  if job_setgid != -1, but job_setuid == -1, we get:

    fchown (script_fd, -1, job_setgid);

However, something like the following is also too simplistic...

    fchown (script_fd,
      job_setuid == -1 ? 0 : job_setuid,
      job_setgid == -1 ? 0 : job_setgid);

... since it doesn't take account of user jobs (and in my snippet above could allow privilege
escalation).

- Resource Limits/OOM/Priority

The fact that the setgid+setuid calls come *after* the chroot+user session code means we're
effectively allowing non-privileged (system) jobs to elevate their resource limits, OOM score and
priority. It could be argued that these are after all system jobs, so why not allow such behaviour?
But until compelling examples are given, I'd prefer we take the cautious approach and disallowed
this behaviour. Again, to avoid confusion we should document in init.5 that system jobs running as
non-privileged users cannot elevate their resource limits beyond that users limits.

* Testing

Yes, I appreciate the issues testing some of these scenarios. It will admittedly complicated by
adding setuid+setgid support to the already interesting combination of user jobs and chroot support
 What we need is a fully automated set of tests for these features. Effort is being put into this
for the current Ubuntu cycle.

What I would recommend is adding some tests to util/tests/test_user_sessions.sh that...

  - essentially duplicate the tests you've created in test_parse_job.c to ensure that say specifying
multiple values after the setuid stanza fails as expected.

  - ensure 'setuid root' fails as expected
  - ensure 'setdid root' fails as expected
  - ensure 'setgid <group>' works (assuming <group> is the users primary group).
  - ensure 'setgid <group>' works (assuming <group> is a valid supplementary group).

Also, could you add a test to init/tests/test_job_process.c that ensures it is possible to run a job
which specifies the *current* user and group of the user running the tests (essentially specifying
"setuid `id -u`" and "setgid `id -g`").

review: Needs Fixing
lp:~broder/upstart/drop-privileges updated
1336. By Evan Broder

* init/man/init.5: Correct spelling typo and clarify that system jobs
which drop privilege are still system jobs, not user jobs.

1337. By Evan Broder

* contrib/vim/syntax/upstart.vim: Add the new setuid and setgid
  stanzas

1338. By Evan Broder

* init/tests/test_job_process.c, util/tests/test_user_sessions.sh:
  Test setuid and setgid stanzas as thoroughly as an unprivileged user
  can (i.e. make sure dropping to yourself works, and escalating to
  anything else doesn't)

1339. By Evan Broder

* init/job_process.c: Cast signed constants to uid_t and gid_t before
  comparing them with the same to correct warnings from the
  build. uid_t and gid_t are unsigned, but -1 is still their dummy
  value

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'contrib/vim/syntax/upstart.vim'
--- contrib/vim/syntax/upstart.vim 2011-06-14 13:53:27 +0000
+++ contrib/vim/syntax/upstart.vim 2011-12-07 15:52:24 +0000
@@ -33,7 +33,7 @@
33" one argument33" one argument
34syn keyword upstartStatement description author version instance expect34syn keyword upstartStatement description author version instance expect
35syn keyword upstartStatement pid kill normal console env exit export35syn keyword upstartStatement pid kill normal console env exit export
36syn keyword upstartStatement umask nice oom chroot chdir exec36syn keyword upstartStatement umask nice oom chroot chdir exec setiud setgid
3737
38" two arguments38" two arguments
39syn keyword upstartStatement limit39syn keyword upstartStatement limit
4040
=== modified file 'init/errors.h'
--- init/errors.h 2011-05-12 20:42:28 +0000
+++ init/errors.h 2011-12-07 15:52:24 +0000
@@ -36,6 +36,8 @@
3636
37 /* Errors while handling job processes */37 /* Errors while handling job processes */
38 JOB_PROCESS_ERROR,38 JOB_PROCESS_ERROR,
39 JOB_PROCESS_INVALID_SETUID,
40 JOB_PROCESS_INVALID_SETGID,
3941
40 /* Errors while parsing configuration files */42 /* Errors while parsing configuration files */
41 PARSE_ILLEGAL_INTERVAL,43 PARSE_ILLEGAL_INTERVAL,
@@ -59,6 +61,8 @@
59#define ENVIRON_UNKNOWN_PARAM_STR N_("Unknown parameter")61#define ENVIRON_UNKNOWN_PARAM_STR N_("Unknown parameter")
60#define ENVIRON_EXPECTED_OPERATOR_STR N_("Expected operator")62#define ENVIRON_EXPECTED_OPERATOR_STR N_("Expected operator")
61#define ENVIRON_MISMATCHED_BRACES_STR N_("Mismatched braces")63#define ENVIRON_MISMATCHED_BRACES_STR N_("Mismatched braces")
64#define JOB_PROCESS_INVALID_SETUID_STR N_("Invalid setuid user name does not exist")
65#define JOB_PROCESS_INVALID_SETGID_STR N_("Invalid setgid group name does not exist")
62#define PARSE_ILLEGAL_INTERVAL_STR N_("Illegal interval, expected number of seconds")66#define PARSE_ILLEGAL_INTERVAL_STR N_("Illegal interval, expected number of seconds")
63#define PARSE_ILLEGAL_EXIT_STR N_("Illegal exit status, expected integer")67#define PARSE_ILLEGAL_EXIT_STR N_("Illegal exit status, expected integer")
64#define PARSE_ILLEGAL_SIGNAL_STR N_("Illegal signal status, expected integer")68#define PARSE_ILLEGAL_SIGNAL_STR N_("Illegal signal status, expected integer")
6569
=== modified file 'init/job_class.c'
--- init/job_class.c 2011-08-11 20:47:00 +0000
+++ init/job_class.c 2011-12-07 15:52:24 +0000
@@ -216,6 +216,9 @@
216 class->chroot = NULL;216 class->chroot = NULL;
217 class->chdir = NULL;217 class->chdir = NULL;
218218
219 class->setuid = NULL;
220 class->setgid = NULL;
221
219 class->deleted = FALSE;222 class->deleted = FALSE;
220 class->debug = FALSE;223 class->debug = FALSE;
221224
222225
=== modified file 'init/job_class.h'
--- init/job_class.h 2011-08-11 20:47:00 +0000
+++ init/job_class.h 2011-12-07 15:52:24 +0000
@@ -156,6 +156,8 @@
156 * @limits: resource limits indexed by resource,156 * @limits: resource limits indexed by resource,
157 * @chroot: root directory of process (implies @chdir if not set),157 * @chroot: root directory of process (implies @chdir if not set),
158 * @chdir: working directory of process,158 * @chdir: working directory of process,
159 * @setuid: user name to drop to before starting process,
160 * @setgid: group name to drop to before starting process,
159 * @deleted: whether job should be deleted when finished.161 * @deleted: whether job should be deleted when finished.
160 *162 *
161 * This structure holds the configuration of a known task or service that163 * This structure holds the configuration of a known task or service that
@@ -206,6 +208,8 @@
206 struct rlimit *limits[RLIMIT_NLIMITS];208 struct rlimit *limits[RLIMIT_NLIMITS];
207 char *chroot;209 char *chroot;
208 char *chdir;210 char *chdir;
211 char *setuid;
212 char *setgid;
209213
210 int deleted;214 int deleted;
211 int debug;215 int debug;
212216
=== modified file 'init/job_process.c'
--- init/job_process.c 2011-08-11 21:08:52 +0000
+++ init/job_process.c 2011-12-07 15:52:24 +0000
@@ -41,6 +41,7 @@
41#include <utmp.h>41#include <utmp.h>
42#include <utmpx.h>42#include <utmpx.h>
43#include <pwd.h>43#include <pwd.h>
44#include <grp.h>
4445
45#include <nih/macros.h>46#include <nih/macros.h>
46#include <nih/alloc.h>47#include <nih/alloc.h>
@@ -380,6 +381,8 @@
380 FILE *fd;381 FILE *fd;
381 int user_job = FALSE;382 int user_job = FALSE;
382 nih_local char *user_dir = NULL;383 nih_local char *user_dir = NULL;
384 uid_t job_setuid = -1;
385 gid_t job_setgid = -1;
383386
384387
385 nih_assert (class != NULL);388 nih_assert (class != NULL);
@@ -654,6 +657,67 @@
654 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHDIR, 0);657 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHDIR, 0);
655 }658 }
656659
660 /* Change the user and group of the process to the one
661 * configured in the job. We must wait until now to lookup the
662 * UID and GID from the names to accommodate both chroot
663 * session jobs and jobs with a chroot stanza.
664 */
665 if (class->setuid) {
666 /* Without resetting errno, it's impossible to
667 * distinguish between a non-existent user and and
668 * error during lookup */
669 errno = 0;
670 struct passwd *pwd = getpwnam (class->setuid);
671 if (! pwd) {
672 if (errno != 0) {
673 nih_error_raise_system ();
674 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWNAM, 0);
675 } else {
676 nih_error_raise (JOB_PROCESS_INVALID_SETUID,
677 JOB_PROCESS_INVALID_SETUID_STR);
678 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_BAD_SETUID, 0);
679 }
680 }
681
682 job_setuid = pwd->pw_uid;
683 /* This will be overridden if setgid is also set: */
684 job_setgid = pwd->pw_gid;
685 }
686
687 if (class->setgid) {
688 errno = 0;
689 struct group *grp = getgrnam (class->setgid);
690 if (! grp) {
691 if (errno != 0) {
692 nih_error_raise_system ();
693 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETGRNAM, 0);
694 } else {
695 nih_error_raise (JOB_PROCESS_INVALID_SETGID,
696 JOB_PROCESS_INVALID_SETGID_STR);
697 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_BAD_SETGID, 0);
698 }
699 }
700
701 job_setgid = grp->gr_gid;
702 }
703
704 if (script_fd != -1 &&
705 (job_setuid != (uid_t) -1 || job_setgid != (gid_t) -1) &&
706 fchown (script_fd, job_setuid, job_setgid) < 0) {
707 nih_error_raise_system ();
708 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHOWN, 0);
709 }
710
711 if (job_setgid != (gid_t) -1 && setgid (job_setgid) < 0) {
712 nih_error_raise_system ();
713 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0);
714 }
715
716 if (job_setuid != (uid_t)-1 && setuid (job_setuid) < 0) {
717 nih_error_raise_system ();
718 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETUID, 0);
719 }
720
657 /* Reset all the signal handlers back to their default handling so721 /* Reset all the signal handlers back to their default handling so
658 * the child isn't unexpectedly ignoring any, and so we won't722 * the child isn't unexpectedly ignoring any, and so we won't
659 * surprisingly handle them before we've exec()d the new process.723 * surprisingly handle them before we've exec()d the new process.
@@ -880,6 +944,24 @@
880 err, _("unable to execute: %s"),944 err, _("unable to execute: %s"),
881 strerror (err->errnum)));945 strerror (err->errnum)));
882 break;946 break;
947 case JOB_PROCESS_ERROR_GETPWNAM:
948 err->error.message = NIH_MUST (nih_sprintf (
949 err, _("unable to getpwnam: %s"),
950 strerror (err->errnum)));
951 break;
952 case JOB_PROCESS_ERROR_GETGRNAM:
953 err->error.message = NIH_MUST (nih_sprintf (
954 err, _("unable to getgrnam: %s"),
955 strerror (err->errnum)));
956 break;
957 case JOB_PROCESS_ERROR_BAD_SETUID:
958 err->error.message = NIH_MUST (nih_sprintf (
959 err, _("unable to find setuid user")));
960 break;
961 case JOB_PROCESS_ERROR_BAD_SETGID:
962 err->error.message = NIH_MUST (nih_sprintf (
963 err, _("unable to find setgid group")));
964 break;
883 case JOB_PROCESS_ERROR_SETUID:965 case JOB_PROCESS_ERROR_SETUID:
884 err->error.message = NIH_MUST (nih_sprintf (966 err->error.message = NIH_MUST (nih_sprintf (
885 err, _("unable to setuid: %s"),967 err, _("unable to setuid: %s"),
886968
=== modified file 'init/job_process.h'
--- init/job_process.h 2011-07-25 14:08:47 +0000
+++ init/job_process.h 2011-12-07 15:52:24 +0000
@@ -57,6 +57,10 @@
57 JOB_PROCESS_ERROR_CHDIR,57 JOB_PROCESS_ERROR_CHDIR,
58 JOB_PROCESS_ERROR_PTRACE,58 JOB_PROCESS_ERROR_PTRACE,
59 JOB_PROCESS_ERROR_EXEC,59 JOB_PROCESS_ERROR_EXEC,
60 JOB_PROCESS_ERROR_GETPWNAM,
61 JOB_PROCESS_ERROR_GETGRNAM,
62 JOB_PROCESS_ERROR_BAD_SETUID,
63 JOB_PROCESS_ERROR_BAD_SETGID,
60 JOB_PROCESS_ERROR_SETUID,64 JOB_PROCESS_ERROR_SETUID,
61 JOB_PROCESS_ERROR_SETGID,65 JOB_PROCESS_ERROR_SETGID,
62 JOB_PROCESS_ERROR_CHOWN66 JOB_PROCESS_ERROR_CHOWN
6367
=== modified file 'init/man/init.5'
--- init/man/init.5 2011-07-25 15:01:24 +0000
+++ init/man/init.5 2011-12-07 15:52:24 +0000
@@ -659,6 +659,32 @@
659.B unlimited659.B unlimited
660may be specified for either.660may be specified for either.
661.\"661.\"
662.TP
663.B setuid \fIUSERNAME
664Changes to the user
665.I USERNAME
666before running the job's process.
667
668If this stanza is unspecified, the job will run as root in the case of
669system jobs, and as the user in the case of User Jobs.
670
671Note that System jobs using the setuid stanza are still system jobs,
672and can not be controlled by an unprivileged user, even if the setuid
673stanza specifies that user.
674.\"
675.TP
676.B setgid \fIGROUPNAME
677Changes to the group
678.I GROUPNAME
679before running the job's process.
680
681If this stanza is unspecified, the primary group of the user specified
682in the
683.B setuid
684block is used. If both stanzas are unspecified, the job will run with
685its group ID set to 0 in the case of system jobs, and as the primary
686group of the user in the case of User Jobs.
687.\"
662.SS Override File Handling688.SS Override File Handling
663Override files allow a jobs environment to be changed without modifying689Override files allow a jobs environment to be changed without modifying
664the jobs configuration file. Rules governing override files:690the jobs configuration file. Rules governing override files:
665691
=== modified file 'init/parse_job.c'
--- init/parse_job.c 2011-06-06 12:52:08 +0000
+++ init/parse_job.c 2011-12-07 15:52:24 +0000
@@ -209,6 +209,14 @@
209 const char *file, size_t len,209 const char *file, size_t len,
210 size_t *pos, size_t *lineno)210 size_t *pos, size_t *lineno)
211 __attribute__ ((warn_unused_result));211 __attribute__ ((warn_unused_result));
212static int stanza_setuid (JobClass *class, NihConfigStanza *stanza,
213 const char *file, size_t len,
214 size_t *pos, size_t *lineno)
215 __attribute__ ((warn_unused_result));
216static int stanza_setgid (JobClass *class, NihConfigStanza *stanza,
217 const char *file, size_t len,
218 size_t *pos, size_t *lineno)
219 __attribute__ ((warn_unused_result));
212static int stanza_debug (JobClass *class, NihConfigStanza *stanza,220static int stanza_debug (JobClass *class, NihConfigStanza *stanza,
213 const char *file, size_t len,221 const char *file, size_t len,
214 size_t *pos, size_t *lineno)222 size_t *pos, size_t *lineno)
@@ -253,6 +261,8 @@
253 { "limit", (NihConfigHandler)stanza_limit },261 { "limit", (NihConfigHandler)stanza_limit },
254 { "chroot", (NihConfigHandler)stanza_chroot },262 { "chroot", (NihConfigHandler)stanza_chroot },
255 { "chdir", (NihConfigHandler)stanza_chdir },263 { "chdir", (NihConfigHandler)stanza_chdir },
264 { "setuid", (NihConfigHandler)stanza_setuid },
265 { "setgid", (NihConfigHandler)stanza_setgid },
256 { "debug", (NihConfigHandler)stanza_debug },266 { "debug", (NihConfigHandler)stanza_debug },
257 { "manual", (NihConfigHandler)stanza_manual },267 { "manual", (NihConfigHandler)stanza_manual },
258268
@@ -2538,3 +2548,77 @@
25382548
2539 return nih_config_skip_comment (file, len, pos, lineno);2549 return nih_config_skip_comment (file, len, pos, lineno);
2540}2550}
2551
2552/**
2553 * stanza_setuid:
2554 * @class: job class being parsed,
2555 * @stanza: stanza found,
2556 * @file: file or string to parse,
2557 * @len: length of @file,
2558 * @pos: offset within @file,
2559 * @lineno: line number.
2560 *
2561 * Parse a setuid stanza from @file, extracting a single argument
2562 * containing a user name.
2563 *
2564 * Returns: zero on success, negative value on error.
2565 **/
2566static int
2567stanza_setuid (JobClass *class,
2568 NihConfigStanza *stanza,
2569 const char *file,
2570 size_t len,
2571 size_t *pos,
2572 size_t *lineno)
2573{
2574 nih_assert (class != NULL);
2575 nih_assert (stanza != NULL);
2576 nih_assert (file != NULL);
2577 nih_assert (pos != NULL);
2578
2579 if (class->setuid)
2580 nih_unref (class->setuid, class);
2581
2582 class->setuid = nih_config_next_arg (class, file, len, pos, lineno);
2583 if (! class->setuid)
2584 return -1;
2585
2586 return nih_config_skip_comment (file, len, pos, lineno);
2587}
2588
2589/**
2590 * stanza_setgid:
2591 * @class: job class being parsed,
2592 * @stanza: stanza found,
2593 * @file: file or string to parse,
2594 * @len: length of @file,
2595 * @pos: offset within @file,
2596 * @lineno: line number.
2597 *
2598 * Parse a setgid stanza from @file, extracting a single argument
2599 * containing a group name.
2600 *
2601 * Returns: zero on success, negative value on error.
2602 **/
2603static int
2604stanza_setgid (JobClass *class,
2605 NihConfigStanza *stanza,
2606 const char *file,
2607 size_t len,
2608 size_t *pos,
2609 size_t *lineno)
2610{
2611 nih_assert (class != NULL);
2612 nih_assert (stanza != NULL);
2613 nih_assert (file != NULL);
2614 nih_assert (pos != NULL);
2615
2616 if (class->setgid)
2617 nih_unref (class->setgid, class);
2618
2619 class->setgid = nih_config_next_arg (class, file, len, pos, lineno);
2620 if (! class->setgid)
2621 return -1;
2622
2623 return nih_config_skip_comment (file, len, pos, lineno);
2624}
25412625
=== modified file 'init/tests/test_job_class.c'
--- init/tests/test_job_class.c 2011-06-06 17:05:11 +0000
+++ init/tests/test_job_class.c 2011-12-07 15:52:24 +0000
@@ -139,6 +139,10 @@
139139
140 TEST_EQ_P (class->chroot, NULL);140 TEST_EQ_P (class->chroot, NULL);
141 TEST_EQ_P (class->chdir, NULL);141 TEST_EQ_P (class->chdir, NULL);
142
143 TEST_EQ_P (class->setuid, NULL);
144 TEST_EQ_P (class->setgid, NULL);
145
142 TEST_FALSE (class->deleted);146 TEST_FALSE (class->deleted);
143147
144 nih_free (class);148 nih_free (class);
145149
=== modified file 'init/tests/test_job_process.c'
--- init/tests/test_job_process.c 2011-06-06 17:05:11 +0000
+++ init/tests/test_job_process.c 2011-12-07 15:52:24 +0000
@@ -38,6 +38,8 @@
38#include <unistd.h>38#include <unistd.h>
39#include <utmp.h>39#include <utmp.h>
40#include <utmpx.h>40#include <utmpx.h>
41#include <pwd.h>
42#include <grp.h>
4143
42#include <nih/macros.h>44#include <nih/macros.h>
43#include <nih/string.h>45#include <nih/string.h>
@@ -124,13 +126,15 @@
124void126void
125test_run (void)127test_run (void)
126{128{
127 JobClass *class = NULL;129 JobClass *class = NULL;
128 Job *job = NULL;130 Job *job = NULL;
129 FILE *output;131 FILE *output;
130 struct stat statbuf;132 struct stat statbuf;
131 char filename[PATH_MAX], buf[80];133 char filename[PATH_MAX], buf[80];
132 int ret = -1, status, first;134 int ret = -1, status, first;
133 siginfo_t info;135 siginfo_t info;
136 struct passwd *pwd;
137 struct group *grp;
134138
135 TEST_FUNCTION ("job_process_run");139 TEST_FUNCTION ("job_process_run");
136 job_class_init ();140 job_class_init ();
@@ -787,6 +791,44 @@
787791
788 nih_free (class);792 nih_free (class);
789 }793 }
794
795 /* Check that we can succesfully setuid and setgid to
796 * ourselves. This should always work, privileged or
797 * otherwise.
798 */
799 TEST_FEATURE ("with setuid me");
800 TEST_ALLOC_FAIL {
801 TEST_ALLOC_SAFE {
802 class = job_class_new (NULL, "test", NULL);
803 class->process[PROCESS_MAIN] = process_new (class);
804 class->process[PROCESS_MAIN]->command = nih_sprintf (
805 class->process[PROCESS_MAIN],
806 "touch %s", filename);
807
808 pwd = getpwuid (getuid ());
809 TEST_NE (pwd, NULL);
810 class->setuid = nih_strdup (class, pwd->pw_name);
811
812 grp = getgrgid (getgid ());
813 TEST_NE (grp, NULL);
814 class->setuid = nih_strdup (class, grp->gr_name);
815
816 job = job_new (class, "");
817 job->goal = JOB_START;
818 job->state = JOB_SPAWNED;
819 }
820
821 ret = job_process_run (job, PROCESS_MAIN);
822 TEST_EQ (ret, 0);
823
824 TEST_NE (job->pid[PROCESS_MAIN], 0);
825
826 waitpid (job->pid[PROCESS_MAIN], NULL, 0);
827 TEST_EQ (stat (filename, &statbuf), 0);
828
829 unlink (filename);
830 nih_free (class);
831 }
790}832}
791833
792834
793835
=== modified file 'init/tests/test_parse_job.c'
--- init/tests/test_parse_job.c 2011-06-06 12:52:08 +0000
+++ init/tests/test_parse_job.c 2011-12-07 15:52:24 +0000
@@ -7933,6 +7933,238 @@
7933 nih_free (err);7933 nih_free (err);
7934}7934}
79357935
7936void
7937test_stanza_setuid (void)
7938{
7939 JobClass*job;
7940 NihError *err;
7941 size_t pos, lineno;
7942 char buf[1024];
7943
7944 TEST_FUNCTION ("stanza_setuid");
7945
7946 /* Check that a setuid stanza with an argument results in it
7947 * being stored in the job.
7948 */
7949 TEST_FEATURE ("with single argument");
7950 strcpy (buf, "setuid www-data\n");
7951
7952 TEST_ALLOC_FAIL {
7953 pos = 0;
7954 lineno = 1;
7955 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf),
7956 &pos, &lineno);
7957
7958 if (test_alloc_failed) {
7959 TEST_EQ_P (job, NULL);
7960
7961 err = nih_error_get ();
7962 TEST_EQ (err->number, ENOMEM);
7963 nih_free (err);
7964
7965 continue;
7966 }
7967
7968 TEST_EQ (pos, strlen (buf));
7969 TEST_EQ (lineno, 2);
7970
7971 TEST_ALLOC_SIZE (job, sizeof (JobClass));
7972
7973 TEST_ALLOC_PARENT (job->setuid, job);
7974 TEST_EQ_STR (job->setuid, "www-data");
7975
7976 nih_free (job);
7977 }
7978
7979
7980 /* Check that the last of multiple setuid stanzas is used.
7981 */
7982 TEST_FEATURE ("with multiple stanzas");
7983 strcpy (buf, "setuid www-data\n");
7984 strcat (buf, "setuid pulse\n");
7985
7986 TEST_ALLOC_FAIL {
7987 pos = 0;
7988 lineno = 1;
7989 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf),
7990 &pos, &lineno);
7991
7992 if (test_alloc_failed) {
7993 TEST_EQ_P (job, NULL);
7994
7995 err = nih_error_get ();
7996 TEST_EQ (err->number, ENOMEM);
7997 nih_free (err);
7998
7999 continue;
8000 }
8001
8002 TEST_EQ (pos, strlen (buf));
8003 TEST_EQ (lineno, 3);
8004
8005 TEST_ALLOC_SIZE (job, sizeof (JobClass));
8006
8007 TEST_ALLOC_PARENT (job->setuid, job);
8008 TEST_EQ_STR (job->setuid, "pulse");
8009
8010 nih_free (job);
8011 }
8012
8013
8014 /* Check that a setuid stanza without an argument results in
8015 * a syntax error.
8016 */
8017 TEST_FEATURE ("with missing argument");
8018 strcpy (buf, "setuid\n");
8019
8020 pos = 0;
8021 lineno = 1;
8022 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf), &pos, &lineno);
8023
8024 TEST_EQ_P (job, NULL);
8025
8026 err = nih_error_get ();
8027 TEST_EQ (err->number, NIH_CONFIG_EXPECTED_TOKEN);
8028 TEST_EQ (pos, 6);
8029 TEST_EQ (lineno, 1);
8030 nih_free (err);
8031
8032
8033 /* Check that a setuid stanza with an extra second argument
8034 * results in a syntax error.
8035 */
8036 TEST_FEATURE ("with extra argument");
8037 strcpy (buf, "setuid www-data foo\n");
8038
8039 pos = 0;
8040 lineno = 1;
8041 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf), &pos, &lineno);
8042
8043 TEST_EQ_P (job, NULL);
8044
8045 err = nih_error_get ();
8046 TEST_EQ (err->number, NIH_CONFIG_UNEXPECTED_TOKEN);
8047 TEST_EQ (pos, 16);
8048 TEST_EQ (lineno, 1);
8049 nih_free (err);
8050}
8051
8052void
8053test_stanza_setgid (void)
8054{
8055 JobClass*job;
8056 NihError *err;
8057 size_t pos, lineno;
8058 char buf[1024];
8059
8060 TEST_FUNCTION ("stanza_setgid");
8061
8062 /* Check that a setgid stanza with an argument results in it
8063 * being stored in the job.
8064 */
8065 TEST_FEATURE ("with single argument");
8066 strcpy (buf, "setgid kvm\n");
8067
8068 TEST_ALLOC_FAIL {
8069 pos = 0;
8070 lineno = 1;
8071 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf),
8072 &pos, &lineno);
8073
8074 if (test_alloc_failed) {
8075 TEST_EQ_P (job, NULL);
8076
8077 err = nih_error_get ();
8078 TEST_EQ (err->number, ENOMEM);
8079 nih_free (err);
8080
8081 continue;
8082 }
8083
8084 TEST_EQ (pos, strlen (buf));
8085 TEST_EQ (lineno, 2);
8086
8087 TEST_ALLOC_SIZE (job, sizeof (JobClass));
8088
8089 TEST_ALLOC_PARENT (job->setgid, job);
8090 TEST_EQ_STR (job->setgid, "kvm");
8091
8092 nih_free (job);
8093 }
8094
8095
8096 /* Check that the last of multiple setgid stanzas is used.
8097 */
8098 TEST_FEATURE ("with multiple stanzas");
8099 strcpy (buf, "setgid kvm\n");
8100 strcat (buf, "setgid fuse\n");
8101
8102 TEST_ALLOC_FAIL {
8103 pos = 0;
8104 lineno = 1;
8105 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf),
8106 &pos, &lineno);
8107
8108 if (test_alloc_failed) {
8109 TEST_EQ_P (job, NULL);
8110
8111 err = nih_error_get ();
8112 TEST_EQ (err->number, ENOMEM);
8113 nih_free (err);
8114
8115 continue;
8116 }
8117
8118 TEST_EQ (pos, strlen (buf));
8119 TEST_EQ (lineno, 3);
8120
8121 TEST_ALLOC_SIZE (job, sizeof (JobClass));
8122
8123 TEST_ALLOC_PARENT (job->setgid, job);
8124 TEST_EQ_STR (job->setgid, "fuse");
8125
8126 nih_free (job);
8127 }
8128
8129
8130 /* Check that a setgid stanza without an argument results in
8131 * a syntax error.
8132 */
8133 TEST_FEATURE ("with missing argument");
8134 strcpy (buf, "setgid\n");
8135
8136 pos = 0;
8137 lineno = 1;
8138 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf), &pos, &lineno);
8139
8140 TEST_EQ_P (job, NULL);
8141
8142 err = nih_error_get ();
8143 TEST_EQ (err->number, NIH_CONFIG_EXPECTED_TOKEN);
8144 TEST_EQ (pos, 6);
8145 TEST_EQ (lineno, 1);
8146 nih_free (err);
8147
8148
8149 /* Check that a setgid stanza with an extra second argument
8150 * results in a syntax error.
8151 */
8152 TEST_FEATURE ("with extra argument");
8153 strcpy (buf, "setgid kvm foo\n");
8154
8155 pos = 0;
8156 lineno = 1;
8157 job = parse_job (NULL, NULL, NULL, "test", buf, strlen (buf), &pos, &lineno);
8158
8159 TEST_EQ_P (job, NULL);
8160
8161 err = nih_error_get ();
8162 TEST_EQ (err->number, NIH_CONFIG_UNEXPECTED_TOKEN);
8163 TEST_EQ (pos, 11);
8164 TEST_EQ (lineno, 1);
8165 nih_free (err);
8166}
8167
7936int8168int
7937main (int argc,8169main (int argc,
7938 char *argv[])8170 char *argv[])
@@ -7979,6 +8211,8 @@
7979 test_stanza_limit ();8211 test_stanza_limit ();
7980 test_stanza_chroot ();8212 test_stanza_chroot ();
7981 test_stanza_chdir ();8213 test_stanza_chdir ();
8214 test_stanza_setuid ();
8215 test_stanza_setgid ();
79828216
7983 return 0;8217 return 0;
7984}8218}
79858219
=== modified file 'util/tests/test_user_sessions.sh'
--- util/tests/test_user_sessions.sh 2011-07-25 14:49:17 +0000
+++ util/tests/test_user_sessions.sh 2011-12-07 15:52:24 +0000
@@ -470,6 +470,45 @@
470 rm -f "$job_file"470 rm -f "$job_file"
471}471}
472472
473test_user_job_setuid_setgid()
474{
475 group="user job with setuid and setgid me"
476 job_name="setuid_setgid_me_test"
477 script="\
478setuid $(id -un)
479setgid $(id -gn)
480exec true"
481 test_user_job "$group" "$job_name" "$script" no ""
482
483 TEST_GROUP "user job with setuid and setgid root"
484 script="\
485setuid root
486setgid root
487exec true"
488
489 job_name="setuid_setgid_root_test"
490 job_file="${test_dir}/${job_name}.conf"
491 job="${test_dir_suffix}/${job_name}"
492
493 echo "$script" > $job_file
494
495 ensure_job_known "$job" "$job_name"
496
497 TEST_FEATURE "ensure job fails to start as root"
498 cmd="start ${job}"
499 output=$(eval "$cmd")
500 rc=$?
501 TEST_EQ "$cmd" $rc 1
502
503 TEST_FEATURE "ensure 'start' indicates job failure"
504 error=$(echo "$output"|grep failed)
505 TEST_NE "error" "$error" ""
506
507 TEST_FEATURE "ensure 'initctl' does not list job"
508 initctl list|grep -q "^$job stop/waiting" || \
509 TEST_FAILED "job $job_name not listed as stopped"
510}
511
473test_user_jobs()512test_user_jobs()
474{513{
475 test_user_job_binary514 test_user_job_binary
@@ -480,6 +519,8 @@
480 test_user_job_single_line_script_task519 test_user_job_single_line_script_task
481 test_user_job_multi_line_script_task520 test_user_job_multi_line_script_task
482521
522 test_user_job_setuid_setgid
523
483 test_user_emit_events524 test_user_emit_events
484}525}
485526

Subscribers

People subscribed via source and target branches