~jamesodhunt/upstart/bug-1197225

« back to all changes in this revision

Viewing changes to init/job_process.c

  • Committer: James Hunt
  • Date: 2013-05-28 12:12:29 UTC
  • mfrom: (1475.1.7 upstart)
  • Revision ID: james.hunt@ubuntu.com-20130528121229-jij7bcc8hvo4jq12
Merge of lp:~mdeslaur/upstart/apparmor-support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
67
67
#include "errors.h"
68
68
#include "control.h"
69
69
#include "xdg.h"
 
70
#include "apparmor.h"
70
71
 
71
72
 
72
73
/**
701
702
                close (pty_slave);
702
703
        }
703
704
 
704
 
        /* Set resource limits for the process, skipping over any that
705
 
         * aren't set in the job class such that they inherit from
706
 
         * ourselves (and we inherit from kernel defaults).
 
705
        /* Switch to the specified AppArmor profile, but only for the main
 
706
           process, so we don't confine the pre- and post- processes.
707
707
         */
708
 
        for (i = 0; i < RLIMIT_NLIMITS; i++) {
709
 
                if (! class->limits[i])
710
 
                        continue;
711
 
 
712
 
                if (setrlimit (i, class->limits[i]) < 0) {
 
708
        if ((class->apparmor_switch) && (process == PROCESS_MAIN)) {
 
709
                nih_local char *profile = NULL;
 
710
 
 
711
                /* Use the environment to expand the AppArmor profile name
 
712
                 */
 
713
                profile = NIH_SHOULD (environ_expand (NULL,
 
714
                                                      class->apparmor_switch,
 
715
                                                      environ));
 
716
 
 
717
                if (! profile) {
 
718
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SECURITY, 0);
 
719
                }
 
720
 
 
721
                if (apparmor_switch (profile) < 0) {
 
722
                        nih_error_raise_system ();
 
723
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SECURITY, 0);
 
724
                }
 
725
        }
 
726
 
 
727
        if (process != PROCESS_SECURITY) {
 
728
                /* Set resource limits for the process, skipping over any that
 
729
                 * aren't set in the job class such that they inherit from
 
730
                 * ourselves (and we inherit from kernel defaults).
 
731
                 */
 
732
                for (i = 0; i < RLIMIT_NLIMITS; i++) {
 
733
                        if (! class->limits[i])
 
734
                                continue;
 
735
 
 
736
                        if (setrlimit (i, class->limits[i]) < 0) {
 
737
                                nih_error_raise_system ();
 
738
                                job_process_error_abort (fds[1],
 
739
                                                         JOB_PROCESS_ERROR_RLIMIT, i);
 
740
                        }
 
741
                }
 
742
 
 
743
                /* Set the file mode creation mask; this is one of the few operations
 
744
                 * that can never fail.
 
745
                 */
 
746
                umask (class->umask);
 
747
 
 
748
                /* Adjust the process priority ("nice level").
 
749
                 */
 
750
                if (class->nice != JOB_NICE_INVALID &&
 
751
                    setpriority (PRIO_PROCESS, 0, class->nice) < 0) {
713
752
                        nih_error_raise_system ();
714
753
                        job_process_error_abort (fds[1],
715
 
                                                 JOB_PROCESS_ERROR_RLIMIT, i);
 
754
                                                 JOB_PROCESS_ERROR_PRIORITY, 0);
716
755
                }
717
 
        }
718
 
 
719
 
        /* Set the file mode creation mask; this is one of the few operations
720
 
         * that can never fail.
721
 
         */
722
 
        umask (class->umask);
723
 
 
724
 
        /* Adjust the process priority ("nice level").
725
 
         */
726
 
        if (class->nice != JOB_NICE_INVALID &&
727
 
            setpriority (PRIO_PROCESS, 0, class->nice) < 0) {
728
 
                nih_error_raise_system ();
729
 
                job_process_error_abort (fds[1],
730
 
                                         JOB_PROCESS_ERROR_PRIORITY, 0);
731
 
        }
732
 
 
733
 
        /* Adjust the process OOM killer priority.
734
 
         */
735
 
        if (class->oom_score_adj != JOB_DEFAULT_OOM_SCORE_ADJ) {
736
 
                int oom_value;
737
 
                snprintf (filename, sizeof (filename),
738
 
                          "/proc/%d/oom_score_adj", getpid ());
739
 
                oom_value = class->oom_score_adj;
740
 
                fd = fopen (filename, "w");
741
 
                if ((! fd) && (errno == ENOENT)) {
 
756
 
 
757
                /* Adjust the process OOM killer priority.
 
758
                 */
 
759
                if (class->oom_score_adj != JOB_DEFAULT_OOM_SCORE_ADJ) {
 
760
                        int oom_value;
742
761
                        snprintf (filename, sizeof (filename),
743
 
                                  "/proc/%d/oom_adj", getpid ());
744
 
                        oom_value = (class->oom_score_adj
745
 
                                     * ((class->oom_score_adj < 0) ? 17 : 15)) / 1000;
 
762
                                  "/proc/%d/oom_score_adj", getpid ());
 
763
                        oom_value = class->oom_score_adj;
746
764
                        fd = fopen (filename, "w");
747
 
                }
748
 
                if (! fd) {
749
 
                        nih_error_raise_system ();
750
 
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_OOM_ADJ, 0);
751
 
                } else {
752
 
                        fprintf (fd, "%d\n", oom_value);
753
 
 
754
 
                        if (fclose (fd)) {
 
765
                        if ((! fd) && (errno == ENOENT)) {
 
766
                                snprintf (filename, sizeof (filename),
 
767
                                          "/proc/%d/oom_adj", getpid ());
 
768
                                oom_value = (class->oom_score_adj
 
769
                                             * ((class->oom_score_adj < 0) ? 17 : 15)) / 1000;
 
770
                                fd = fopen (filename, "w");
 
771
                        }
 
772
                        if (! fd) {
755
773
                                nih_error_raise_system ();
756
774
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_OOM_ADJ, 0);
757
 
                        }
758
 
                }
759
 
        }
760
 
 
761
 
        /* Handle changing a chroot session job prior to dealing with
762
 
         * the 'chroot' stanza.
763
 
         */
764
 
        if (class->session && class->session->chroot) {
765
 
                if (chroot (class->session->chroot) < 0) {
766
 
                        nih_error_raise_system ();
767
 
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHROOT, 0);
768
 
                }
769
 
        }
770
 
 
771
 
        /* Change the root directory, confining path resolution within it;
772
 
         * we do this before the working directory call so that is always
773
 
         * relative to the new root.
774
 
         */
775
 
        if (class->chroot) {
776
 
                if (chroot (class->chroot) < 0) {
777
 
                        nih_error_raise_system ();
778
 
                        job_process_error_abort (fds[1],
779
 
                                                 JOB_PROCESS_ERROR_CHROOT, 0);
780
 
                }
781
 
        }
782
 
 
783
 
        /* Change the working directory of the process, either to the one
784
 
         * configured in the job, or to the root directory of the filesystem
785
 
         * (or at least relative to the chroot).
786
 
         */
787
 
        if (class->chdir || user_mode == FALSE) {
788
 
                if (chdir (class->chdir ? class->chdir : "/") < 0) {
789
 
                        nih_error_raise_system ();
790
 
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHDIR, 0);
791
 
                }
792
 
        }
793
 
 
794
 
        /* Change the user and group of the process to the one
795
 
         * configured in the job. We must wait until now to lookup the
796
 
         * UID and GID from the names to accommodate both chroot
797
 
         * session jobs and jobs with a chroot stanza.
798
 
         */
799
 
        if (class->setuid) {
800
 
                /* Without resetting errno, it's impossible to
801
 
                 * distinguish between a non-existent user and and
802
 
                 * error during lookup */
803
 
                errno = 0;
804
 
                pwd = getpwnam (class->setuid);
805
 
                if (! pwd) {
806
 
                        if (errno != 0) {
807
 
                                nih_error_raise_system ();
808
 
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWNAM, 0);
809
 
                        } else {
810
 
                                nih_error_raise (JOB_PROCESS_INVALID_SETUID,
811
 
                                                 JOB_PROCESS_INVALID_SETUID_STR);
812
 
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_BAD_SETUID, 0);
813
 
                        }
814
 
                }
815
 
 
816
 
                job_setuid = pwd->pw_uid;
817
 
                /* This will be overridden if setgid is also set: */
818
 
                job_setgid = pwd->pw_gid;
819
 
        }
820
 
 
821
 
        if (class->setgid) {
822
 
                errno = 0;
823
 
                grp = getgrnam (class->setgid);
824
 
                if (! grp) {
825
 
                        if (errno != 0) {
826
 
                                nih_error_raise_system ();
827
 
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETGRNAM, 0);
828
 
                        } else {
829
 
                                nih_error_raise (JOB_PROCESS_INVALID_SETGID,
830
 
                                                 JOB_PROCESS_INVALID_SETGID_STR);
831
 
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_BAD_SETGID, 0);
832
 
                        }
833
 
                }
834
 
 
835
 
                job_setgid = grp->gr_gid;
836
 
        }
837
 
 
838
 
        if (script_fd != -1 &&
839
 
            (job_setuid != (uid_t) -1 || job_setgid != (gid_t) -1) &&
840
 
            fchown (script_fd, job_setuid, job_setgid) < 0) {
841
 
                nih_error_raise_system ();
842
 
                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHOWN, 0);
843
 
        }
844
 
 
845
 
        /* Make sure we always have the needed pwd and grp structs.
846
 
         * Then pass those to initgroups() to setup the user's group list.
847
 
         * Only do that if we're root as initgroups() won't work when non-root. */
848
 
        if (geteuid () == 0) {
849
 
                if (! pwd) {
850
 
                        pwd = getpwuid (geteuid ());
851
 
                        if (! pwd) {
852
 
                                nih_error_raise_system ();
853
 
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWUID, 0);
854
 
                        }
855
 
                }
856
 
 
857
 
                if (! grp) {
858
 
                        grp = getgrgid (getegid ());
859
 
                        if (! grp) {
860
 
                                nih_error_raise_system ();
861
 
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETGRGID, 0);
862
 
                        }
863
 
                }
864
 
 
865
 
                if (pwd && grp) {
866
 
                        if (initgroups (pwd->pw_name, grp->gr_gid) < 0) {
867
 
                                nih_error_raise_system ();
868
 
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_INITGROUPS, 0);
869
 
                        }
870
 
                }
871
 
        }
872
 
 
873
 
        /* Start dropping privileges */
874
 
        if (job_setgid != (gid_t) -1 && setgid (job_setgid) < 0) {
875
 
                nih_error_raise_system ();
876
 
                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0);
877
 
        }
878
 
 
879
 
        if (job_setuid != (uid_t)-1 && setuid (job_setuid) < 0) {
880
 
                nih_error_raise_system ();
881
 
                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETUID, 0);
 
775
                        } else {
 
776
                                fprintf (fd, "%d\n", oom_value);
 
777
 
 
778
                                if (fclose (fd)) {
 
779
                                        nih_error_raise_system ();
 
780
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_OOM_ADJ, 0);
 
781
                                }
 
782
                        }
 
783
                }
 
784
 
 
785
                /* Handle changing a chroot session job prior to dealing with
 
786
                 * the 'chroot' stanza.
 
787
                 */
 
788
                if (class->session && class->session->chroot) {
 
789
                        if (chroot (class->session->chroot) < 0) {
 
790
                                nih_error_raise_system ();
 
791
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHROOT, 0);
 
792
                        }
 
793
                }
 
794
 
 
795
                /* Change the root directory, confining path resolution within it;
 
796
                 * we do this before the working directory call so that is always
 
797
                 * relative to the new root.
 
798
                 */
 
799
                if (class->chroot) {
 
800
                        if (chroot (class->chroot) < 0) {
 
801
                                nih_error_raise_system ();
 
802
                                job_process_error_abort (fds[1],
 
803
                                                         JOB_PROCESS_ERROR_CHROOT, 0);
 
804
                        }
 
805
                }
 
806
 
 
807
                /* Change the working directory of the process, either to the one
 
808
                 * configured in the job, or to the root directory of the filesystem
 
809
                 * (or at least relative to the chroot).
 
810
                 */
 
811
                if (class->chdir || user_mode == FALSE) {
 
812
                        if (chdir (class->chdir ? class->chdir : "/") < 0) {
 
813
                                nih_error_raise_system ();
 
814
                                job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHDIR, 0);
 
815
                        }
 
816
                }
 
817
 
 
818
                /* Change the user and group of the process to the one
 
819
                 * configured in the job. We must wait until now to lookup the
 
820
                 * UID and GID from the names to accommodate both chroot
 
821
                 * session jobs and jobs with a chroot stanza.
 
822
                 */
 
823
                if (class->setuid) {
 
824
                        /* Without resetting errno, it's impossible to
 
825
                         * distinguish between a non-existent user and and
 
826
                         * error during lookup */
 
827
                        errno = 0;
 
828
                        pwd = getpwnam (class->setuid);
 
829
                        if (! pwd) {
 
830
                                if (errno != 0) {
 
831
                                        nih_error_raise_system ();
 
832
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWNAM, 0);
 
833
                                } else {
 
834
                                        nih_error_raise (JOB_PROCESS_INVALID_SETUID,
 
835
                                                         JOB_PROCESS_INVALID_SETUID_STR);
 
836
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_BAD_SETUID, 0);
 
837
                                }
 
838
                        }
 
839
 
 
840
                        job_setuid = pwd->pw_uid;
 
841
                        /* This will be overridden if setgid is also set: */
 
842
                        job_setgid = pwd->pw_gid;
 
843
                }
 
844
 
 
845
                if (class->setgid) {
 
846
                        errno = 0;
 
847
                        grp = getgrnam (class->setgid);
 
848
                        if (! grp) {
 
849
                                if (errno != 0) {
 
850
                                        nih_error_raise_system ();
 
851
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETGRNAM, 0);
 
852
                                } else {
 
853
                                        nih_error_raise (JOB_PROCESS_INVALID_SETGID,
 
854
                                                         JOB_PROCESS_INVALID_SETGID_STR);
 
855
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_BAD_SETGID, 0);
 
856
                                }
 
857
                        }
 
858
 
 
859
                        job_setgid = grp->gr_gid;
 
860
                }
 
861
 
 
862
                if (script_fd != -1 &&
 
863
                    (job_setuid != (uid_t) -1 || job_setgid != (gid_t) -1) &&
 
864
                    fchown (script_fd, job_setuid, job_setgid) < 0) {
 
865
                        nih_error_raise_system ();
 
866
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHOWN, 0);
 
867
                }
 
868
 
 
869
                /* Make sure we always have the needed pwd and grp structs.
 
870
                 * Then pass those to initgroups() to setup the user's group list.
 
871
                 * Only do that if we're root as initgroups() won't work when non-root. */
 
872
                if (geteuid () == 0) {
 
873
                        if (! pwd) {
 
874
                                pwd = getpwuid (geteuid ());
 
875
                                if (! pwd) {
 
876
                                        nih_error_raise_system ();
 
877
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWUID, 0);
 
878
                                }
 
879
                        }
 
880
 
 
881
                        if (! grp) {
 
882
                                grp = getgrgid (getegid ());
 
883
                                if (! grp) {
 
884
                                        nih_error_raise_system ();
 
885
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETGRGID, 0);
 
886
                                }
 
887
                        }
 
888
 
 
889
                        if (pwd && grp) {
 
890
                                if (initgroups (pwd->pw_name, grp->gr_gid) < 0) {
 
891
                                        nih_error_raise_system ();
 
892
                                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_INITGROUPS, 0);
 
893
                                }
 
894
                        }
 
895
                }
 
896
 
 
897
                /* Start dropping privileges */
 
898
                if (job_setgid != (gid_t) -1 && setgid (job_setgid) < 0) {
 
899
                        nih_error_raise_system ();
 
900
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0);
 
901
                }
 
902
 
 
903
                if (job_setuid != (uid_t)-1 && setuid (job_setuid) < 0) {
 
904
                        nih_error_raise_system ();
 
905
                        job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETUID, 0);
 
906
                }
882
907
        }
883
908
 
884
909
        /* Reset all the signal handlers back to their default handling so
923
948
        nih_assert_not_reached ();
924
949
}
925
950
 
 
951
 
926
952
/**
927
953
 * job_process_error_abort:
928
954
 * @fd: writing end of pipe,
1185
1211
                                  err, _("unable to initgroups: %s"),
1186
1212
                                  strerror (err->errnum)));
1187
1213
                break;
 
1214
        case JOB_PROCESS_ERROR_SECURITY:
 
1215
                err->error.message = NIH_MUST (nih_sprintf (
 
1216
                                  err, _("unable to switch security profile: %s"),
 
1217
                                  strerror (err->errnum)));
 
1218
                break;
1188
1219
        default:
1189
1220
                nih_assert_not_reached ();
1190
1221
        }
1640
1671
                 */
1641
1672
                stop = TRUE;
1642
1673
                break;
 
1674
        case PROCESS_SECURITY:
 
1675
                nih_assert (job->state == JOB_SECURITY);
 
1676
 
 
1677
                /* We should always fail the job if the security profile
 
1678
                 * failed to load
 
1679
                 */
 
1680
                if (status) {
 
1681
                        failed = TRUE;
 
1682
                        stop = TRUE;
 
1683
                }
 
1684
                break;
1643
1685
        case PROCESS_PRE_START:
1644
1686
                nih_assert (job->state == JOB_PRE_START);
1645
1687