Skip to content
Permalink
Browse files

fix unsafe JSON construction

  • Loading branch information...
zouyee committed Aug 14, 2019
1 parent 125fb72 commit 9fc113b75c6b2208bbc76d8b7309444edb923e4a
@@ -17,15 +17,17 @@ limitations under the License.
package controller

import (
"encoding/json"
"fmt"
"sync"

apps "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/klog"
)
@@ -213,20 +215,24 @@ func (m *PodControllerRefManager) AdoptPod(pod *v1.Pod) error {
}
// Note that ValidateOwnerReferences() will reject this patch if another
// OwnerReference exists with controller=true.
addControllerPatch := fmt.Sprintf(
`{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
m.controllerKind.GroupVersion(), m.controllerKind.Kind,
m.Controller.GetName(), m.Controller.GetUID(), pod.UID)
return m.podControl.PatchPod(pod.Namespace, pod.Name, []byte(addControllerPatch))

patchBytes, err := ownerRefControllerPatch(&m.BaseControllerRefManager, m.controllerKind, pod.UID)
if err != nil {
return err
}
return m.podControl.PatchPod(pod.Namespace, pod.Name, patchBytes)
}

// ReleasePod sends a patch to free the pod from the control of the controller.
// It returns the error if the patching fails. 404 and 422 errors are ignored.
func (m *PodControllerRefManager) ReleasePod(pod *v1.Pod) error {
klog.V(2).Infof("patching pod %s_%s to remove its controllerRef to %s/%s:%s",
pod.Namespace, pod.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.Controller.GetName())
deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.Controller.GetUID(), pod.UID)
err := m.podControl.PatchPod(pod.Namespace, pod.Name, []byte(deleteOwnerRefPatch))
patchBytes, err := deleteOwnerRefStrategicMergePatch(pod.UID, m.Controller.GetUID())
if err != nil {
return err
}
err = m.podControl.PatchPod(pod.Namespace, pod.Name, patchBytes)
if err != nil {
if errors.IsNotFound(err) {
// If the pod no longer exists, ignore it.
@@ -335,20 +341,23 @@ func (m *ReplicaSetControllerRefManager) AdoptReplicaSet(rs *apps.ReplicaSet) er
}
// Note that ValidateOwnerReferences() will reject this patch if another
// OwnerReference exists with controller=true.
addControllerPatch := fmt.Sprintf(
`{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
m.controllerKind.GroupVersion(), m.controllerKind.Kind,
m.Controller.GetName(), m.Controller.GetUID(), rs.UID)
return m.rsControl.PatchReplicaSet(rs.Namespace, rs.Name, []byte(addControllerPatch))
patchBytes, err := ownerRefControllerPatch(&m.BaseControllerRefManager, m.controllerKind, rs.UID)
if err != nil {
return err
}
return m.rsControl.PatchReplicaSet(rs.Namespace, rs.Name, patchBytes)
}

// ReleaseReplicaSet sends a patch to free the ReplicaSet from the control of the Deployment controller.
// It returns the error if the patching fails. 404 and 422 errors are ignored.
func (m *ReplicaSetControllerRefManager) ReleaseReplicaSet(replicaSet *apps.ReplicaSet) error {
klog.V(2).Infof("patching ReplicaSet %s_%s to remove its controllerRef to %s/%s:%s",
replicaSet.Namespace, replicaSet.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.Controller.GetName())
deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.Controller.GetUID(), replicaSet.UID)
err := m.rsControl.PatchReplicaSet(replicaSet.Namespace, replicaSet.Name, []byte(deleteOwnerRefPatch))
patchBytes, err := deleteOwnerRefStrategicMergePatch(replicaSet.UID, m.Controller.GetUID())
if err != nil {
return err
}
err = m.rsControl.PatchReplicaSet(replicaSet.Namespace, replicaSet.Name, patchBytes)
if err != nil {
if errors.IsNotFound(err) {
// If the ReplicaSet no longer exists, ignore it.
@@ -470,20 +479,24 @@ func (m *ControllerRevisionControllerRefManager) AdoptControllerRevision(history
}
// Note that ValidateOwnerReferences() will reject this patch if another
// OwnerReference exists with controller=true.
addControllerPatch := fmt.Sprintf(
`{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
m.controllerKind.GroupVersion(), m.controllerKind.Kind,
m.Controller.GetName(), m.Controller.GetUID(), history.UID)
return m.crControl.PatchControllerRevision(history.Namespace, history.Name, []byte(addControllerPatch))
patchBytes, err := ownerRefControllerPatch(&m.BaseControllerRefManager, m.controllerKind, history.UID)
if err != nil {
return err
}
return m.crControl.PatchControllerRevision(history.Namespace, history.Name, patchBytes)
}

// ReleaseControllerRevision sends a patch to free the ControllerRevision from the control of its controller.
// It returns the error if the patching fails. 404 and 422 errors are ignored.
func (m *ControllerRevisionControllerRefManager) ReleaseControllerRevision(history *apps.ControllerRevision) error {
klog.V(2).Infof("patching ControllerRevision %s_%s to remove its controllerRef to %s/%s:%s",
history.Namespace, history.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.Controller.GetName())
deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.Controller.GetUID(), history.UID)
err := m.crControl.PatchControllerRevision(history.Namespace, history.Name, []byte(deleteOwnerRefPatch))
patchBytes, err := deleteOwnerRefStrategicMergePatch(history.UID, m.Controller.GetUID())
if err != nil {
return err
}

err = m.crControl.PatchControllerRevision(history.Namespace, history.Name, patchBytes)
if err != nil {
if errors.IsNotFound(err) {
// If the ControllerRevision no longer exists, ignore it.
@@ -499,3 +512,57 @@ func (m *ControllerRevisionControllerRefManager) ReleaseControllerRevision(histo
}
return err
}

type objectForMergePatch struct {
ObjectMetaForMergePatch `json:"metadata"`
}

type ObjectMetaForMergePatch struct {
UID types.UID `json:"uid"`
OwnerReferences []map[string]string `json:"ownerReferences"`
}

func deleteOwnerRefStrategicMergePatch(dependentUID types.UID, ownerUIDs ...types.UID) ([]byte, error) {
var pieces []map[string]string
for _, ownerUID := range ownerUIDs {
pieces = append(pieces, map[string]string{"$patch": "delete", "uid": string(ownerUID)})
}
patch := ObjectMetaForMergePatch{}
patch.UID = dependentUID
patch.OwnerReferences = pieces

patchBytes, err := json.Marshal(objectForMergePatch{patch})
if err != nil {
return nil, err
}
return patchBytes, nil
}

type objectForPatch struct {
ObjectMetaForPatch `json:"metadata"`
}

type ObjectMetaForPatch struct {
OwnerReferences []metav1.OwnerReference `json:"ownerReferences"`
UID types.UID `json:"uid"`
}

func ownerRefControllerPatch(bcr *BaseControllerRefManager, controllerKind schema.GroupVersionKind, uid types.UID) ([]byte, error) {
blockOwnerDeletion := true
isController := true
addControllerPatch := ObjectMetaForPatch{}
addControllerPatch.OwnerReferences = append(addControllerPatch.OwnerReferences, metav1.OwnerReference{
APIVersion: controllerKind.GroupVersion().String(),
Kind: controllerKind.Kind,
Name: bcr.Controller.GetName(),
UID: bcr.Controller.GetUID(),
Controller: &isController,
BlockOwnerDeletion: &blockOwnerDeletion,
})
addControllerPatch.UID = uid
patchBytes, err := json.Marshal(objectForPatch{addControllerPatch})
if err != nil {
return nil, err
}
return patchBytes, nil
}
@@ -19,7 +19,6 @@ package garbagecollector
import (
"encoding/json"
"fmt"
"strings"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
@@ -29,13 +28,29 @@ import (
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
)

type objectForMergePatch struct {
ObjectMetaForMergePatch `json:"metadata"`
}

type ObjectMetaForMergePatch struct {
UID types.UID `json:"uid"`
OwnerReferences []map[string]string `json:"ownerReferences"`
}

func deleteOwnerRefStrategicMergePatch(dependentUID types.UID, ownerUIDs ...types.UID) []byte {
var pieces []string
var pieces []map[string]string
for _, ownerUID := range ownerUIDs {
pieces = append(pieces, fmt.Sprintf(`{"$patch":"delete","uid":"%s"}`, ownerUID))
pieces = append(pieces, map[string]string{"$patch": "delete", "uid": string(ownerUID)})
}
patch := ObjectMetaForMergePatch{}
patch.UID = dependentUID
patch.OwnerReferences = pieces

patchBytes, err := json.Marshal(objectForMergePatch{patch})
if err != nil {
return []byte{}
}
patch := fmt.Sprintf(`{"metadata":{"ownerReferences":[%s],"uid":"%s"}}`, strings.Join(pieces, ","), dependentUID)
return []byte(patch)
return patchBytes
}

// getMetadata tries getting object metadata from local cache, and sends GET request to apiserver when
@@ -18,6 +18,7 @@ package history

import (
"bytes"
"encoding/json"
"fmt"
"hash/fnv"
"sort"
@@ -290,17 +291,41 @@ func (rh *realHistory) DeleteControllerRevision(revision *apps.ControllerRevisio
return rh.client.AppsV1().ControllerRevisions(revision.Namespace).Delete(revision.Name, nil)
}

type objectForPatch struct {
ObjectMetaForPatch `json:"metadata"`
}

// ObjectMetaForPatch define object meta struct for patch operation
type ObjectMetaForPatch struct {
OwnerReferences []metav1.OwnerReference `json:"ownerReferences"`
UID types.UID `json:"uid"`
}

func (rh *realHistory) AdoptControllerRevision(parent metav1.Object, parentKind schema.GroupVersionKind, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
blockOwnerDeletion := true
isController := true
// Return an error if the parent does not own the revision
if owner := metav1.GetControllerOf(revision); owner != nil {
return nil, fmt.Errorf("attempt to adopt revision owned by %v", owner)
}
addControllerPatch := ObjectMetaForPatch{}
addControllerPatch.OwnerReferences = append(addControllerPatch.OwnerReferences, metav1.OwnerReference{
APIVersion: parentKind.GroupVersion().String(),
Kind: parentKind.Kind,
Name: parent.GetName(),
UID: parent.GetUID(),
Controller: &isController,
BlockOwnerDeletion: &blockOwnerDeletion,
})
addControllerPatch.UID = revision.UID

patchBytes, err := json.Marshal(objectForPatch{addControllerPatch})
if err != nil {
return nil, err
}
// Use strategic merge patch to add an owner reference indicating a controller ref
return rh.client.AppsV1().ControllerRevisions(parent.GetNamespace()).Patch(revision.GetName(),
types.StrategicMergePatchType, []byte(fmt.Sprintf(
`{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
parentKind.GroupVersion().String(), parentKind.Kind,
parent.GetName(), parent.GetUID(), revision.UID)))
types.StrategicMergePatchType, patchBytes)
}

func (rh *realHistory) ReleaseControllerRevision(parent metav1.Object, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
@@ -158,14 +158,24 @@ func GetZoneKey(node *v1.Node) string {
return region + ":\x00:" + failureDomain
}

type nodeForPatch struct {
nodeStatusForPatch `json:"status"`
}

type nodeStatusForPatch struct {
Conditions []v1.NodeCondition `json:"conditions"`
}

// SetNodeCondition updates specific node condition with patch operation.
func SetNodeCondition(c clientset.Interface, node types.NodeName, condition v1.NodeCondition) error {
generatePatch := func(condition v1.NodeCondition) ([]byte, error) {
raw, err := json.Marshal(&[]v1.NodeCondition{condition})
patch := nodeStatusForPatch{}
patch.Conditions = append(patch.Conditions, condition)
patchBytes, err := json.Marshal(nodeForPatch{patch})
if err != nil {
return nil, err
}
return []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw)), nil
return patchBytes, nil
}
condition.LastHeartbeatTime = metav1.NewTime(time.Now())
patch, err := generatePatch(condition)
@@ -176,15 +186,24 @@ func SetNodeCondition(c clientset.Interface, node types.NodeName, condition v1.N
return err
}

type nodeForMergePatch struct {
nodeSpecForMergePatch `json:"spec"`
}

type nodeSpecForMergePatch struct {
PodCIDR string `json:"podCIDR"`
PodCIDRs []string `json:"podCIDRs,omitempty"`
}

// PatchNodeCIDR patches the specified node's CIDR to the given value.
func PatchNodeCIDR(c clientset.Interface, node types.NodeName, cidr string) error {
raw, err := json.Marshal(cidr)
patch := nodeSpecForMergePatch{PodCIDR: cidr}

patchBytes, err := json.Marshal(nodeForMergePatch{patch})
if err != nil {
return fmt.Errorf("failed to json.Marshal CIDR: %v", err)
}

patchBytes := []byte(fmt.Sprintf(`{"spec":{"podCIDR":%s}}`, raw))

if _, err := c.CoreV1().Nodes().Patch(string(node), types.StrategicMergePatchType, patchBytes); err != nil {
return fmt.Errorf("failed to patch node CIDR: %v", err)
}
@@ -193,18 +212,14 @@ func PatchNodeCIDR(c clientset.Interface, node types.NodeName, cidr string) erro

// PatchNodeCIDRs patches the specified node.CIDR=cidrs[0] and node.CIDRs to the given value.
func PatchNodeCIDRs(c clientset.Interface, node types.NodeName, cidrs []string) error {
rawCidrs, err := json.Marshal(cidrs)
if err != nil {
return fmt.Errorf("failed to json.Marshal CIDRs: %v", err)
}
// set the pod cidrs list and set the old pod cidr field
patch := nodeSpecForMergePatch{PodCIDR: cidrs[0]}
patch.PodCIDRs = append(patch.PodCIDRs, cidrs...)

rawCidr, err := json.Marshal(cidrs[0])
patchBytes, err := json.Marshal(nodeForMergePatch{patch})
if err != nil {
return fmt.Errorf("failed to json.Marshal CIDR: %v", err)
}

// set the pod cidrs list and set the old pod cidr field
patchBytes := []byte(fmt.Sprintf(`{"spec":{"podCIDR":%s , "podCIDRs":%s}}`, rawCidr, rawCidrs))
klog.V(4).Infof("cidrs patch bytes are:%s", string(patchBytes))
if _, err := c.CoreV1().Nodes().Patch(string(node), types.StrategicMergePatchType, patchBytes); err != nil {
return fmt.Errorf("failed to patch node CIDR: %v", err)

0 comments on commit 9fc113b

Please sign in to comment.
You can’t perform that action at this time.