zsh-workers
 help / color / mirror / code / Atom feed
7c4a1be356122c8a584e3511e284fa808f6f8271 blob 8181 bytes (raw)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
 
# This file contains tests related to the PRIVILEGED option. In order to run,
# it requires that the test process itself have super-user privileges (or that
# one of the environment variables described below be set). This can be achieved
# via, e.g., `sudo make check TESTNUM=P`.
#
# Optionally, the environment variables ZSH_TEST_UNPRIVILEGED_UID and/or
# ZSH_TEST_UNPRIVILEGED_GID may be set to UID:EUID or GID:EGID pairs, where the
# two IDs in each pair are different, non-0 IDs valid on the system being used
# to run the tests. (The UIDs must both be non-0 to effectively test downgrading
# of privileges, and they must be non-matching to test auto-enabling of
# PRIVILEGED and to ensure that disabling PRIVILEGED correctly resets the saved
# UID. Technically GID 0 is not special, but for simplicity's sake we apply the
# same requirements here.)
#
# If either of the aforementioned environment variables is not set, the test
# script will try to use the UID/GID of the test directory, if not 0, for the
# two effective IDs. (This is intended to work around issues that might occur
# when e.g. the test directory lives under a home directory with mode 0700.
# Unfortunately, if this is the case, it will not be possible to use anything
# besides the directory owner or root as the test shell's EUID -- maintainers
# take note.) Otherwise, the script will pick the first >0 ID(s) from the
# passwd/group databases on the current system.
#
# If either variable is set, the tests will run, but they will likely fail
# without super-user privileges.

%prep

  # Mind your empty lines here. The logic in this %prep section is somewhat
  # complex compared to most others; to avoid lots of nested/duplicated
  # conditions we need to make sure that this all gets executed as a single
  # function from which we can return early
  [[ $EUID == 0 || -n $ZSH_TEST_UNPRIVILEGED_UID$ZSH_TEST_UNPRIVILEGED_GID ]] || {
    ZTST_unimplemented='PRIVILEGED tests require super-user privileges (or env var)'
    return 1
  }
  (( $+commands[perl] )) || { # @todo Eliminate this dependency with a C wrapper?
    ZTST_unimplemented='PRIVILEGED tests require Perl'
    return 1
  }
  grep -qE '#define HAVE_SETRES?UID' $ZTST_testdir/../config.h || {
    ZTST_unimplemented='PRIVILEGED tests require setreuid()/setresuid()'
    return 1
  }
  #
  ruid= euid= rgid= egid=
  #
  if [[ -n $ZSH_TEST_UNPRIVILEGED_UID ]]; then
    ruid=${ZSH_TEST_UNPRIVILEGED_UID%%:*}
    euid=${ZSH_TEST_UNPRIVILEGED_UID##*:}
  else
    print -ru$ZTST_fd 'Selecting unprivileged UID:EUID pair automatically'
    # See above for why we do this
    zmodload -sF zsh/stat b:zstat && euid=${"$( zstat +uid -- $ZTST_testdir )":#0}
    local tmp=$( getent passwd 2> /dev/null || < /etc/passwd )
    # Note: Some awks require -v and its argument to be separate
    ruid=$( awk -F: -v u=${euid:-0} '$3 > 0 && $3 != u { print $3; exit; }' <<< $tmp )
    euid=${euid:-"$( awk -F: -v u=$ruid '$3 > u { print $3; exit; }' <<< $tmp )"}
  fi
  #
  if [[ -n $ZSH_TEST_UNPRIVILEGED_GID ]]; then
    rgid=${ZSH_TEST_UNPRIVILEGED_GID%%:*}
    egid=${ZSH_TEST_UNPRIVILEGED_GID##*:}
  else
    print -ru$ZTST_fd 'Selecting unprivileged GID:EGID pair automatically'
    # See above again -- this shouldn't have the same impact as the UID, though
    zmodload -sF zsh/stat b:zstat && egid=${"$( zstat +gid -- $ZTST_testdir )":#0}
    local tmp=$( getent group 2> /dev/null || < /etc/group )
    # Note: Some awks require -v and its argument to be separate
    rgid=$( awk -F: -v g=${egid:-0} '$3 > 0 && $3 != g { print $3; exit; }' <<< $tmp )
    egid=${egid:="$( awk -F: -v g=$rgid '$3 > g { print $3; exit; }' <<< $tmp )"}
  fi
  #
  [[ $ruid/$euid == <1->/<1-> && $ruid != $euid ]] || ruid= euid=
  [[ $rgid/$egid == <1->/<1-> && $rgid != $egid ]] || rgid= egid=
  #
  [[ -n $ruid && -n $euid ]] || {
    ZTST_unimplemented='PRIVILEGED tests require unprivileged UID:EUID'
    return 1
  }
  [[ -n $rgid || -n $egid ]] || {
    ZTST_unimplemented='PRIVILEGED tests require unprivileged GID:EGID'
    return 1
  }
  #
  print -ru$ZTST_fd \
    "Using unprivileged UID $ruid, EUID $euid, GID $rgid, EGID $egid"
  #
  # Execute process with specified UID and EUID
  # $1     => Real UID
  # $2     => Effective UID
  # $3     => Real GID
  # $4     => Effective GID
  # $5 ... => Command + args to execute (must NOT be a shell command string)
  re_exec() {
    perl -e '
      die("re_exec: not enough arguments") unless (@ARGV >= 5);
      my ($ruid, $euid, $rgid, $egid, @cmd) = @ARGV;
      foreach my $id ($ruid, $euid, $rgid, $egid) {
        die("re_exec: invalid ID: $id") unless ($id =~ /^(-1|\d+)$/a);
      }
      $< = 0 + $ruid if ($ruid >= 0);
      $> = 0 + $euid if ($euid >= 0);
      $( = 0 + $rgid if ($rgid >= 0);
      $) = 0 + $egid if ($egid >= 0);
      exec(@cmd);
      die("re_exec: exec failed: $!");
    ' -- "$@"
  }
  #
  # Convenience wrapper for re_exec to call `zsh -c`
  # -* ... => (optional) Command-line options to zsh
  # $1     => Real UID
  # $2     => Effective UID
  # $3     => Real GID
  # $4     => Effective GID
  # $5 ... => zsh command string; multiple strings are joined by \n
  re_zsh() {
    local -a opts
    while [[ $1 == -[A-Za-z-]* ]]; do
      opts+=( $1 )
      shift
    done
    re_exec "$1" "$2" "$3" "$4" $ZTST_exe $opts -fc \
      "MODULE_PATH=${(q)MODULE_PATH}; ${(F)@[5,-1]}"
  }
  #
  # Return one or more random unused UIDs
  # $1 ... => Names of parameters to store UIDs in
  get_unused_uid() {
    while (( $# )); do
      local i_=0 uid_=
      until [[ -n $uid_ ]]; do
        (( ++i_ > 99 )) && return 1
        uid_=$RANDOM
        id $uid_ &> /dev/null || break
        uid_=
      done
      : ${(P)1::=$uid_}
      shift
    done
  }

%test

  re_zsh $euid $euid -1 -1 'echo $UID/$EUID $options[privileged]'
  re_zsh $ruid $euid -1 -1 'echo $UID/$EUID $options[privileged]'
0q:PRIVILEGED automatically enabled when RUID != EUID
>$euid/$euid off
>$ruid/$euid on

  re_zsh -1 -1 $rgid $rgid 'echo $GID/$EGID $options[privileged]'
  re_zsh -1 -1 $egid $egid 'echo $GID/$EGID $options[privileged]'
  re_zsh -1 -1 $rgid $egid 'echo $GID/$EGID $options[privileged]'
0q:PRIVILEGED automatically enabled when RGID != EGID
>$rgid/$rgid off
>$egid/$egid off
>$rgid/$egid on

  re_zsh $ruid $euid -1 -1 'unsetopt privileged; echo $UID/$EUID'
0q:EUID set to RUID after disabling PRIVILEGED
*?zsh:unsetopt:1: PRIVILEGED: supplementary group list not changed *
*?zsh:unsetopt:1: can't change option: privileged
>$ruid/$ruid

  re_zsh 0 $euid -1 -1 'unsetopt privileged && echo $UID/$EUID'
0:RUID/EUID set to 0/0 when privileged after disabling PRIVILEGED
>0/0

  re_zsh $ruid $euid -1 -1 "unsetopt privileged; UID=$euid" ||
  re_zsh $ruid $euid -1 -1 "unsetopt privileged; EUID=$euid"
1:not possible to regain EUID when unprivileged after disabling PRIVILEGED
*?zsh:unsetopt:1: PRIVILEGED: supplementary group list not changed *
*?zsh:unsetopt:1: can't change option: privileged
*?zsh:1: failed to change user ID: *
*?zsh:unsetopt:1: PRIVILEGED: supplementary group list not changed *
*?zsh:unsetopt:1: can't change option: privileged
*?zsh:1: failed to change effective user ID: *

  re_zsh -1 -1 $rgid $egid 'unsetopt privileged && echo $GID/$EGID'
0q:EGID set to RGID after disabling PRIVILEGED
>$rgid/$rgid

# This test also confirms that we can't revert to the original EUID's primary
# GID, which initgroups() may reset the EGID to on some systems
  re_zsh $ruid 0 $rgid 0 'unsetopt privileged; GID=0' ||
  re_zsh $ruid 0 $rgid 0 'unsetopt privileged; EGID=0'
1:not possible to regain EGID when unprivileged after disabling PRIVILEGED
*?zsh:1: failed to change group ID: *
*?zsh:1: failed to change effective group ID: *

  local rruid
  grep -qF '#define HAVE_INITGROUPS' $ZTST_testdir/../config.h || {
    ZTST_skip='initgroups() not available'
    return 1
  }
  get_unused_uid rruid || {
    ZTST_skip="Can't get unused UID"
    return 1
  }
  re_zsh $rruid 0 -1 -1 'unsetopt privileged'
1:getpwuid() fails with non-existent RUID and 0 EUID
*?zsh:unsetopt:1: can't drop privileges; failed to get user information *
*?zsh:unsetopt:1: can't change option: privileged
debug log:

solving 7c4a1be35 ...
found 7c4a1be35 in https://git.vuxu.org/mirror/zsh/

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).