diff --git a/Dockerfile b/Dockerfile
index 607d5a86..86ea8d7b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -97,7 +97,7 @@ RUN set -x \
        && rm -rf "$GOPATH"
 
 # Install crictl
-ENV CRICTL_COMMIT 16e6fe4d7199c5689db4630a9330e6a8a12cecd1
+ENV CRICTL_COMMIT 9ff5e8f78a4182ab8d5ba9bcccdda5f338600eab
 RUN set -x \
        && export GOPATH="$(mktemp -d)" \
        && git clone https://github.com/kubernetes-incubator/cri-tools.git "$GOPATH/src/github.com/kubernetes-incubator/cri-tools" \
diff --git a/contrib/test/integration/build/cri-tools.yml b/contrib/test/integration/build/cri-tools.yml
index e314225e..9a117f3c 100644
--- a/contrib/test/integration/build/cri-tools.yml
+++ b/contrib/test/integration/build/cri-tools.yml
@@ -4,7 +4,7 @@
   git:
     repo: "https://github.com/kubernetes-incubator/cri-tools.git"
     dest: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-tools"
-    version: "16e6fe4d7199c5689db4630a9330e6a8a12cecd1"
+    version: "9ff5e8f78a4182ab8d5ba9bcccdda5f338600eab"
 
 - name: install crictl
   command: "/usr/bin/go install github.com/kubernetes-incubator/cri-tools/cmd/crictl"
diff --git a/oci/oci.go b/oci/oci.go
index 756be44b..1cf1964b 100644
--- a/oci/oci.go
+++ b/oci/oci.go
@@ -549,6 +549,25 @@ func (r *Runtime) ExecSync(c *Container, command []string, timeout int64) (resp
 	}, nil
 }
 
+// UpdateContainer updates container resources
+func (r *Runtime) UpdateContainer(c *Container, res *rspec.LinuxResources) error {
+	cmd := exec.Command(r.Path(c), "update", "--resources", "-", c.id)
+	var stdout bytes.Buffer
+	var stderr bytes.Buffer
+	cmd.Stdout = &stdout
+	cmd.Stderr = &stderr
+	jsonResources, err := json.Marshal(res)
+	if err != nil {
+		return err
+	}
+	cmd.Stdin = bytes.NewReader(jsonResources)
+
+	if err := cmd.Run(); err != nil {
+		return fmt.Errorf("updating resources for container %q failed: %v %v (%v)", c.id, stderr.String(), stdout.String(), err)
+	}
+	return nil
+}
+
 func waitContainerStop(ctx context.Context, c *Container, timeout time.Duration) error {
 	done := make(chan struct{})
 	// we could potentially re-use "done" channel to exit the loop on timeout
diff --git a/server/container_update_resources.go b/server/container_update_resources.go
index aa2c3734..e434e8a9 100644
--- a/server/container_update_resources.go
+++ b/server/container_update_resources.go
@@ -1,13 +1,38 @@
 package server
 
 import (
-	"fmt"
-
+	"github.com/gogo/protobuf/proto"
+	rspec "github.com/opencontainers/runtime-spec/specs-go"
 	"golang.org/x/net/context"
 	pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
 )
 
 // UpdateContainerResources updates ContainerConfig of the container.
 func (s *Server) UpdateContainerResources(ctx context.Context, req *pb.UpdateContainerResourcesRequest) (*pb.UpdateContainerResourcesResponse, error) {
-	return nil, fmt.Errorf("not implemented")
+	c, err := s.GetContainerFromRequest(req.GetContainerId())
+	if err != nil {
+		return nil, err
+	}
+	resources := toOCIResources(req.GetLinux())
+	if err := s.Runtime().UpdateContainer(c, resources); err != nil {
+		return nil, err
+	}
+	return &pb.UpdateContainerResourcesResponse{}, nil
+}
+
+// toOCIResources converts CRI resource constraints to OCI.
+func toOCIResources(r *pb.LinuxContainerResources) *rspec.LinuxResources {
+	return &rspec.LinuxResources{
+		CPU: &rspec.LinuxCPU{
+			Shares: proto.Uint64(uint64(r.GetCpuShares())),
+			Quota:  proto.Int64(r.GetCpuQuota()),
+			Period: proto.Uint64(uint64(r.GetCpuPeriod())),
+			Cpus:   r.GetCpusetCpus(),
+			Mems:   r.GetCpusetMems(),
+		},
+		Memory: &rspec.LinuxMemory{
+			Limit: proto.Int64(r.GetMemoryLimitInBytes()),
+		},
+		// TODO(runcom): OOMScoreAdj is missing
+	}
 }
diff --git a/test/ctr.bats b/test/ctr.bats
index 90f42b68..88a47bc7 100644
--- a/test/ctr.bats
+++ b/test/ctr.bats
@@ -871,3 +871,60 @@ function teardown() {
 	cleanup_pods
 	stop_crio
 }
+
+@test "ctr update resources" {
+	start_crio
+	run crioctl pod run --config "$TESTDATA"/sandbox_config.json
+	echo "$output"
+	[ "$status" -eq 0 ]
+	pod_id="$output"
+	run crioctl ctr create --config "$TESTDATA"/container_redis.json --pod "$pod_id"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	ctr_id="$output"
+	run crioctl ctr start --id "$ctr_id"
+	echo "$output"
+	[ "$status" -eq 0 ]
+
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/memory/memory.limit_in_bytes"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "209715200" ]]
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/cpu/cpu.shares"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "512" ]]
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "10000" ]]
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "20000" ]]
+
+	run crictl update --memory 524288000 --cpu-period 20000 --cpu-quota 10000 --cpu-share 256 "$ctr_id"
+	echo "$output"
+	[ "$status" -eq 0 ]
+
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/memory/memory.limit_in_bytes"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "524288000" ]]
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/cpu/cpu.shares"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "256" ]]
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "20000" ]]
+	run crioctl ctr execsync --id "$ctr_id" sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us"
+	echo "$output"
+	[ "$status" -eq 0 ]
+	[[ "$output" =~ "10000" ]]
+
+	cleanup_ctrs
+	cleanup_pods
+	stop_crio
+}
diff --git a/test/testdata/container_redis.json b/test/testdata/container_redis.json
index 638aba4f..20f1cbe5 100644
--- a/test/testdata/container_redis.json
+++ b/test/testdata/container_redis.json
@@ -45,6 +45,7 @@
 	"tty": false,
 	"linux": {
 		"resources": {
+			"memory_limit_in_bytes": 209715200,
 			"cpu_period": 10000,
 			"cpu_quota": 20000,
 			"cpu_shares": 512,