diff options
author | Frédéric Buclin <LpSolit@gmail.com> | 2011-08-04 22:08:32 +0200 |
---|---|---|
committer | Frédéric Buclin <LpSolit@gmail.com> | 2011-08-04 22:08:32 +0200 |
commit | 5d70d16f37a866852e6a48ec9fefe3664a6a9a55 (patch) | |
tree | b193cb8a52a93619d408869931126777d8c82bb0 /Bugzilla/Bug.pm | |
parent | b9c01561118c42514055b218f81cb82fa76dbb05 (diff) | |
download | bugzilla-5d70d16f37a866852e6a48ec9fefe3664a6a9a55.tar.gz bugzilla-5d70d16f37a866852e6a48ec9fefe3664a6a9a55.tar.xz |
Bug 653477: (CVE-2011-2380) [SECURITY] Group names can be guessed when creating or editing a bug
r=mkanat a=LpSolit
Diffstat (limited to 'Bugzilla/Bug.pm')
-rw-r--r-- | Bugzilla/Bug.pm | 94 |
1 files changed, 52 insertions, 42 deletions
diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index bf4529f6f..1f0034ff7 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -1622,6 +1622,8 @@ sub _check_dup_id { sub _check_groups { my ($invocant, $group_names, undef, $params) = @_; + + my $bug_id = blessed($invocant) ? $invocant->id : undef; my $product = blessed($invocant) ? $invocant->product_obj : $params->{product}; my %add_groups; @@ -1640,14 +1642,12 @@ sub _check_groups { if !ref $group_names; # First check all the groups they chose to set. + my %args = ( product => $product->name, bug_id => $bug_id, action => 'add' ); foreach my $name (@$group_names) { - my $group = Bugzilla::Group->check( - { name => $name, product => $product, - _error => 'group_restriction_not_allowed' }); + my $group = Bugzilla::Group->check_no_disclose({ %args, name => $name }); if (!$product->group_is_settable($group)) { - ThrowUserError('group_restriction_not_allowed', - { name => $name, product => $product }); + ThrowUserError('group_restriction_not_allowed', { %args, name => $name }); } $add_groups{$group->id} = $group; } @@ -2512,20 +2512,18 @@ sub _set_product { $self->set_target_milestone($tm_name); } } - + if ($product_changed) { - # Remove groups that can't be set in the new product, or that aren't - # active. - # + # Remove groups that can't be set in the new product. # We copy this array because the original array is modified while we're # working, and that confuses "foreach". my @current_groups = @{$self->groups_in}; foreach my $group (@current_groups) { - if (!$group->is_active or !$product->group_is_valid($group)) { + if (!$product->group_is_valid($group)) { $self->remove_group($group); } } - + # Make sure the bug is in all the mandatory groups for the new product. foreach my $group (@{$product->groups_mandatory}) { $self->add_group($group); @@ -2757,18 +2755,25 @@ sub modify_keywords { sub add_group { my ($self, $group) = @_; - # Invalid ids are silently ignored. (We can't tell people whether - # or not a group exists.) - $group = Bugzilla::Group->check($group) if !blessed $group; - return if !$group->is_active or !$group->is_bug_group; + # If the user enters "FoO" but the DB has "Foo", $group->name would + # return "Foo" and thus revealing the existence of the group name. + # So we have to store and pass the name as entered by the user to + # the error message, if we have it. + my $group_name = blessed($group) ? $group->name : $group; + my $args = { name => $group_name, product => $self->product, + bug_id => $self->id, action => 'add' }; + + $group = Bugzilla::Group->check_no_disclose($args) if !blessed $group; + + # If the bug is already in this group, then there is nothing to do. + return if $self->in_group($group); + # Make sure that bugs in this product can actually be restricted # to this group by the current user. $self->product_obj->group_is_settable($group) - || ThrowUserError('group_invalid_restriction', - { product => $self->product, group => $group, - bug => $self }); + || ThrowUserError('group_restriction_not_allowed', $args); # OtherControl people can add groups only during a product change, # and only when the group is not NA for them. @@ -2777,37 +2782,38 @@ sub add_group { if (!$self->{_old_product_name} || $controls->{othercontrol} == CONTROLMAPNA) { - ThrowUserError('group_change_denied', - { bug => $self, group => $group }); + ThrowUserError('group_restriction_not_allowed', $args); } } my $current_groups = $self->groups_in; - if (!grep($group->id == $_->id, @$current_groups)) { - push(@$current_groups, $group); - } + push(@$current_groups, $group); } sub remove_group { my ($self, $group) = @_; - $group = Bugzilla::Group->check($group) if !blessed $group; - - # First, check if this is a valid group for this product. - # You can *always* remove a group that is not valid for this product - # or that is not active, so we don't do any other checks if either of - # those are the case. (Users might remove inactive groups, and set_product - # removes groups that aren't valid for this product.) - # - # This particularly happens when isbuggroup is no longer 1, and we're - # moving a bug to a new product. - if ($group->is_active and $self->product_obj->group_is_valid($group)) { + + # See add_group() for the reason why we store the user input. + my $group_name = blessed($group) ? $group->name : $group; + my $args = { name => $group_name, product => $self->product, + bug_id => $self->id, action => 'remove' }; + + $group = Bugzilla::Group->check_no_disclose($args) if !blessed $group; + + # If the bug isn't in this group, then either the name is misspelled, + # or the group really doesn't exist. Let the user know about this problem. + $self->in_group($group) || ThrowUserError('group_invalid_removal', $args); + + # Check if this is a valid group for this product. You can *always* + # remove a group that is not valid for this product (set_product does this). + # This particularly happens when we're moving a bug to a new product. + # You still have to be a member of an inactive group to remove it. + if ($self->product_obj->group_is_valid($group)) { my $controls = $self->product_obj->group_controls->{$group->id}; - # Nobody can ever remove a Mandatory group. - if ($controls->{membercontrol} == CONTROLMAPMANDATORY) { - ThrowUserError('group_invalid_removal', - { product => $self->product, group => $group, - bug => $self }); + # Nobody can ever remove a Mandatory group, unless it became inactive. + if ($controls->{membercontrol} == CONTROLMAPMANDATORY && $group->is_active) { + ThrowUserError('group_invalid_removal', $args); } # OtherControl people can remove groups only during a product change, @@ -2817,12 +2823,11 @@ sub remove_group { || $controls->{othercontrol} == CONTROLMAPMANDATORY || $controls->{othercontrol} == CONTROLMAPNA) { - ThrowUserError('group_change_denied', - { bug => $self, group => $group }); + ThrowUserError('group_invalid_removal', $args); } } } - + my $current_groups = $self->groups_in; @$current_groups = grep { $_->id != $group->id } @$current_groups; } @@ -3529,6 +3534,11 @@ sub groups_in { return $self->{'groups_in'}; } +sub in_group { + my ($self, $group) = @_; + return grep($_->id == $group->id, @{$self->groups_in}) ? 1 : 0; +} + sub user { my $self = shift; return $self->{'user'} if exists $self->{'user'}; |