CVE-2018-11756 (published 2018-07-23T17:29Z)

In PHP Runtime for Apache OpenWhisk, a Docker action inheriting one of the Docker tags openwhisk/action-php-v7.2:1.0.0 or openwhisk/action-php-v7.1:1.0.1 (or earlier) may allow an attacker to replace the user function inside the container if the user code is vulnerable to code exploitation.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/apache/incubator-openwhisk-runtime-php
commit_details: repo_url: https://github.com/apache/incubator-openwhisk-runtime-php
author: Rodric Rabbah
author_date: 2018-07-07 21:20:35-04:00
msg: Update tests to pick up upstream changes.
repository: repo_url: https://github.com/apache/incubator-openwhisk-runtime-php
repo_name: apache/openwhisk-runtime-php
description: Apache OpenWhisk Runtime PHP supports Apache OpenWhisk functions written in PHP
repo_language: Scala
owner: apache
file_changes: filename: CHANGELOG.md
change_type: ModificationType.MODIFY
diff: @@ -17,6 +17,10 @@
 #
 -->
 
+## 1.0.2
+Changes:
+  - Disallow re-initialization of function.
+
 ## 1.0.1
 
 - Change: Update PHP to 7.1.18

programming_language: Markdown
filename: router.php
change_type: ModificationType.MODIFY
diff: @@ -108,7 +108,7 @@ function init() : array
     $binary = $data['binary'] ?? false;  // code is binary?
 
     if (!$code) {
-        throw new RuntimeException("No code to execute");
+        throw new RuntimeException("Missing main/no code to execute.");
     }
 
     if ($binary) {

programming_language: PHP
filename: CHANGELOG.md
change_type: ModificationType.MODIFY
diff: @@ -17,6 +17,10 @@
 #
 -->
 
+## 1.0.1
+Changes:
+  - Disallow re-initialization of function.
+
 ## 1.0.0
 Initial release
 

programming_language: Markdown
filename: router.php
change_type: ModificationType.MODIFY
diff: @@ -139,7 +139,7 @@ function init() : array
     $binary = $data['binary'] ?? false;  // code is binary?
 
     if (!$code) {
-        throw new RuntimeException("No code to execute");
+        throw new RuntimeException("Missing main/no code to execute.");
     }
 
     if ($binary) {

programming_language: PHP
filename: .pydevproject
change_type: ModificationType.DELETE
diff: @@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?eclipse-pydev version="1.0"?><pydev_project>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
-</pydev_project>

programming_language: unknown
filename: Php7ActionContainerTests.scala
change_type: ModificationType.MODIFY
diff: @@ -27,11 +27,10 @@ import spray.json._
 
 @RunWith(classOf[JUnitRunner])
 abstract class Php7ActionContainerTests extends BasicActionRunnerTests with WskActorSystem {
-  // note: "out" will not be empty as the PHP web server outputs a message when
-  // it starts up
+  // note: "out" will not be empty as the PHP web server outputs a message when it starts up
   val enforceEmptyOutputStream = false
 
-  lazy val phpContainerImageName = "action-php-v7.x"
+  lazy val phpContainerImageName: String = ???
 
   override def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit) = {
     withContainer(phpContainerImageName, env)(code)
@@ -41,30 +40,56 @@ abstract class Php7ActionContainerTests extends BasicActionRunnerTests with WskA
 
   behavior of phpContainerImageName
 
-  testEcho(Seq {
-    (
-      "PHP",
+  override val testNoSourceOrExec = TestConfig("")
+
+  override val testNotReturningJson = {
+    TestConfig(
+      """
+       |<?php
+       |function main(array $args) {
+       |    return "not a json object";
+       |}
+     """.stripMargin,
+      enforceEmptyOutputStream = enforceEmptyOutputStream,
+      enforceEmptyErrorStream = false)
+  }
+
+  override val testInitCannotBeCalledMoreThanOnce = {
+    TestConfig(
       """
-          |<?php
-          |function main(array $args) : array {
-          |    echo 'hello stdout';
-          |    error_log('hello stderr');
-          |    return $args;
-          |}
-          """.stripMargin)
-  })
-
-  testNotReturningJson("""
         |<?php
-        |function main(array $args) {
-        |    return "not a json object";
+        |function main(array $args) : array {
+        |    return $args;
         |}
-        """.stripMargin)
+      """.stripMargin,
+      enforceEmptyOutputStream = enforceEmptyOutputStream)
+  }
 
-  testUnicode(Seq {
-    (
-      "PHP",
+  override val testEntryPointOtherThanMain = {
+    TestConfig(
       """
+        | <?php
+        | function niam(array $args) {
+        |     return $args;
+        | }
+      """.stripMargin,
+      main = "niam",
+      enforceEmptyOutputStream = enforceEmptyOutputStream)
+  }
+
+  override val testEcho = {
+    TestConfig("""
+                 |<?php
+                 |function main(array $args) : array {
+                 |    echo 'hello stdout';
+                 |    error_log('hello stderr');
+                 |    return $args;
+                 |}
+               """.stripMargin)
+  }
+
+  override val testUnicode = {
+    TestConfig("""
          |<?php
          |function main(array $args) : array {
          |    $str = $args['delimiter'] . " ☃ " . $args['delimiter'];
@@ -72,37 +97,37 @@ abstract class Php7ActionContainerTests extends BasicActionRunnerTests with WskA
          |    return  ["winter" => $str];
          |}
          """.stripMargin.trim)
-  })
+  }
 
-  testEnv(
-    Seq {
-      (
-        "PHP",
-        """
-         |<?php
-         |function main(array $args) : array {
-         |    return [
-         |       "env" => $_ENV,
-         |       "api_host" => $_ENV['__OW_API_HOST'],
-         |       "api_key" => $_ENV['__OW_API_KEY'],
-         |       "namespace" => $_ENV['__OW_NAMESPACE'],
-         |       "action_name" => $_ENV['__OW_ACTION_NAME'],
-         |       "activation_id" => $_ENV['__OW_ACTIVATION_ID'],
-         |       "deadline" => $_ENV['__OW_DEADLINE'],
-         |    ];
-         |}
-         """.stripMargin.trim)
-    },
-    enforceEmptyOutputStream)
-
-  testInitCannotBeCalledMoreThanOnce("""
-          |<?php
-          |function main(array $args) : array {
-          |    echo 'hello stdout';
-          |    error_log('hello stderr');
-          |    return $args;
-          |}
-          """.stripMargin)
+  override val testEnv = {
+    TestConfig(
+      """
+        |<?php
+        |function main(array $args) : array {
+        |    return [
+        |       "env" => $_ENV,
+        |       "api_host" => $_ENV['__OW_API_HOST'],
+        |       "api_key" => $_ENV['__OW_API_KEY'],
+        |       "namespace" => $_ENV['__OW_NAMESPACE'],
+        |       "action_name" => $_ENV['__OW_ACTION_NAME'],
+        |       "activation_id" => $_ENV['__OW_ACTIVATION_ID'],
+        |       "deadline" => $_ENV['__OW_DEADLINE'],
+        |    ];
+        |}
+      """.stripMargin.trim,
+      enforceEmptyOutputStream = enforceEmptyOutputStream)
+  }
+
+  override val testLargeInput = {
+    TestConfig("""
+                 |<?php
+                 |function main(array $args) : array {
+                 |    echo 'hello stdout';
+                 |    error_log('hello stderr');
+                 |    return $args;
+                 |}
+               """.stripMargin)
+  }
 
   it should "fail to initialize with bad code" in {
     val (out, err) = withPhp7Container { c =>
@@ -127,19 +152,6 @@ abstract class Php7ActionContainerTests extends BasicActionRunnerTests with WskA
     })
   }
 
-  it should "fail to initialize with no code" in {
-    val (out, err) = withPhp7Container { c =>
-      val code = ""
-
-      val (initCode, error) = c.init(initPayload(code))
-
-      initCode should not be (200)
-      error shouldBe a[Some[_]]
-      error.get shouldBe a[JsObject]
-      error.get.fields("error").toString should include("No code to execute")
-    }
-  }
-
   it should "return some error on action error" in {
     val (out, err) = withPhp7Container { c =>
       val code = """
@@ -467,21 +479,6 @@ abstract class Php7ActionContainerTests extends BasicActionRunnerTests with WskA
     })
   }
 
-  it should "support actions using non-default entry point" in {
-    val (out, err) = withPhp7Container { c =>
-      val code = """
-            | <?php
-            | function niam(array $args) {
-            |     return [result => "it works"];
-            | }
-            """.stripMargin
-
-      c.init(initPayload(code, main = "niam"))._1 should be(200)
-      val (runCode, runRes) = c.run(runPayload(JsObject()))
-      runRes.get.fields.get("result") shouldBe Some(JsString("it works"))
-    }
-  }
-
   it should "support zipped actions using non-default entry point" in {
     val srcs = Seq(Seq("index.php") -> """
                 | <?php

programming_language: Scala