From 73174f870735251e7d4240cdc36983d1bef7db5f Mon Sep 17 00:00:00 2001
From: Craig Ingram <cjingram@google.com>
Date: Fri, 24 Feb 2023 15:24:49 -0500
Subject: [PATCH] Return error for localhost seccomp type with no localhost
 profile defined

---
 pkg/kubelet/kuberuntime/helpers.go            |  66 ++--
 pkg/kubelet/kuberuntime/helpers_test.go       | 350 ++++--------------
 .../kuberuntime_container_linux.go            |  16 +-
 .../kuberuntime_container_linux_test.go       |  22 +-
 pkg/kubelet/kuberuntime/security_context.go   |  15 +-
 5 files changed, 153 insertions(+), 316 deletions(-)

diff --git a/pkg/kubelet/kuberuntime/helpers.go b/pkg/kubelet/kuberuntime/helpers.go
index de289836a8b..6138fc958d7 100644
--- a/pkg/kubelet/kuberuntime/helpers.go
+++ b/pkg/kubelet/kuberuntime/helpers.go
@@ -210,28 +210,32 @@ func toKubeRuntimeStatus(status *runtimeapi.RuntimeStatus) *kubecontainer.Runtim
 	return &kubecontainer.RuntimeStatus{Conditions: conditions}
 }
 
-func fieldProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) string {
+func fieldProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) (string, error) {
 	if scmp == nil {
 		if fallbackToRuntimeDefault {
-			return v1.SeccompProfileRuntimeDefault
+			return v1.SeccompProfileRuntimeDefault, nil
 		}
-		return ""
+		return "", nil
 	}
 	if scmp.Type == v1.SeccompProfileTypeRuntimeDefault {
-		return v1.SeccompProfileRuntimeDefault
-	}
-	if scmp.Type == v1.SeccompProfileTypeLocalhost && scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
-		fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
-		return v1.SeccompLocalhostProfileNamePrefix + fname
+		return v1.SeccompProfileRuntimeDefault, nil
+	}
+	if scmp.Type == v1.SeccompProfileTypeLocalhost {
+		if scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
+			fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
+			return v1.SeccompLocalhostProfileNamePrefix + fname, nil
+		} else {
+			return "", fmt.Errorf("localhostProfile must be set if seccompProfile type is Localhost.")
+		}
 	}
 	if scmp.Type == v1.SeccompProfileTypeUnconfined {
-		return v1.SeccompProfileNameUnconfined
+		return v1.SeccompProfileNameUnconfined, nil
 	}
 
 	if fallbackToRuntimeDefault {
-		return v1.SeccompProfileRuntimeDefault
+		return v1.SeccompProfileRuntimeDefault, nil
 	}
-	return ""
+	return "", nil
 }
 
 func annotationProfile(profile, profileRootPath string) string {
@@ -244,7 +248,7 @@ func annotationProfile(profile, profileRootPath string) string {
 }
 
 func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string]string, containerName string,
-	podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) string {
+	podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) (string, error) {
 	// container fields are applied first
 	if containerSecContext != nil && containerSecContext.SeccompProfile != nil {
 		return fieldProfile(containerSecContext.SeccompProfile, m.seccompProfileRoot, fallbackToRuntimeDefault)
@@ -253,7 +257,7 @@ func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string
 	// if container field does not exist, try container annotation (deprecated)
 	if containerName != "" {
 		if profile, ok := annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName]; ok {
-			return annotationProfile(profile, m.seccompProfileRoot)
+			return annotationProfile(profile, m.seccompProfileRoot), nil
 		}
 	}
 
@@ -264,46 +268,50 @@ func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string
 
 	// as last resort, try to apply pod annotation (deprecated)
 	if profile, ok := annotations[v1.SeccompPodAnnotationKey]; ok {
-		return annotationProfile(profile, m.seccompProfileRoot)
+		return annotationProfile(profile, m.seccompProfileRoot), nil
 	}
 
 	if fallbackToRuntimeDefault {
-		return v1.SeccompProfileRuntimeDefault
+		return v1.SeccompProfileRuntimeDefault, nil
 	}
 
-	return ""
+	return "", nil
 }
 
-func fieldSeccompProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) *runtimeapi.SecurityProfile {
+func fieldSeccompProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) (*runtimeapi.SecurityProfile, error) {
 	if scmp == nil {
 		if fallbackToRuntimeDefault {
 			return &runtimeapi.SecurityProfile{
 				ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
-			}
+			}, nil
 		}
 		return &runtimeapi.SecurityProfile{
 			ProfileType: runtimeapi.SecurityProfile_Unconfined,
-		}
+		}, nil
 	}
 	if scmp.Type == v1.SeccompProfileTypeRuntimeDefault {
 		return &runtimeapi.SecurityProfile{
 			ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
-		}
+		}, nil
 	}
-	if scmp.Type == v1.SeccompProfileTypeLocalhost && scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
-		fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
-		return &runtimeapi.SecurityProfile{
-			ProfileType:  runtimeapi.SecurityProfile_Localhost,
-			LocalhostRef: fname,
+	if scmp.Type == v1.SeccompProfileTypeLocalhost {
+		if scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
+			fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
+			return &runtimeapi.SecurityProfile{
+				ProfileType:  runtimeapi.SecurityProfile_Localhost,
+				LocalhostRef: fname,
+			}, nil
+		} else {
+			return nil, fmt.Errorf("localhostProfile must be set if seccompProfile type is Localhost.")
 		}
 	}
 	return &runtimeapi.SecurityProfile{
 		ProfileType: runtimeapi.SecurityProfile_Unconfined,
-	}
+	}, nil
 }
 
 func (m *kubeGenericRuntimeManager) getSeccompProfile(annotations map[string]string, containerName string,
-	podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) *runtimeapi.SecurityProfile {
+	podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) (*runtimeapi.SecurityProfile, error) {
 	// container fields are applied first
 	if containerSecContext != nil && containerSecContext.SeccompProfile != nil {
 		return fieldSeccompProfile(containerSecContext.SeccompProfile, m.seccompProfileRoot, fallbackToRuntimeDefault)
@@ -317,12 +325,12 @@ func (m *kubeGenericRuntimeManager) getSeccompProfile(annotations map[string]str
 	if fallbackToRuntimeDefault {
 		return &runtimeapi.SecurityProfile{
 			ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
-		}
+		}, nil
 	}
 
 	return &runtimeapi.SecurityProfile{
 		ProfileType: runtimeapi.SecurityProfile_Unconfined,
-	}
+	}, nil
 }
 
 func ipcNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
diff --git a/pkg/kubelet/kuberuntime/helpers_test.go b/pkg/kubelet/kuberuntime/helpers_test.go
index 25065f30411..70ad7250ce2 100644
--- a/pkg/kubelet/kuberuntime/helpers_test.go
+++ b/pkg/kubelet/kuberuntime/helpers_test.go
@@ -242,17 +242,18 @@ func TestFieldProfile(t *testing.T) {
 		scmpProfile     *v1.SeccompProfile
 		rootPath        string
 		expectedProfile string
+		expectedError   string
 	}{
 		{
 			description:     "no seccompProfile should return empty",
 			expectedProfile: "",
 		},
 		{
-			description: "type localhost without profile should return empty",
+			description: "type localhost without profile should return error",
 			scmpProfile: &v1.SeccompProfile{
 				Type: v1.SeccompProfileTypeLocalhost,
 			},
-			expectedProfile: "",
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
 			description: "unknown type should return empty",
@@ -279,7 +280,7 @@ func TestFieldProfile(t *testing.T) {
 			description: "SeccompProfileTypeLocalhost should return localhost",
 			scmpProfile: &v1.SeccompProfile{
 				Type:             v1.SeccompProfileTypeLocalhost,
-				LocalhostProfile: utilpointer.StringPtr("profile.json"),
+				LocalhostProfile: utilpointer.String("profile.json"),
 			},
 			rootPath:        "/test/",
 			expectedProfile: "localhost//test/profile.json",
@@ -287,8 +288,13 @@ func TestFieldProfile(t *testing.T) {
 	}
 
 	for i, test := range tests {
-		seccompProfile := fieldProfile(test.scmpProfile, test.rootPath, false)
-		assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		seccompProfile, err := fieldProfile(test.scmpProfile, test.rootPath, false)
+		if test.expectedError != "" {
+			assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+		} else {
+			assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+			assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		}
 	}
 }
 
@@ -298,17 +304,18 @@ func TestFieldProfileDefaultSeccomp(t *testing.T) {
 		scmpProfile     *v1.SeccompProfile
 		rootPath        string
 		expectedProfile string
+		expectedError   string
 	}{
 		{
 			description:     "no seccompProfile should return runtime/default",
 			expectedProfile: v1.SeccompProfileRuntimeDefault,
 		},
 		{
-			description: "type localhost without profile should return runtime/default",
+			description: "type localhost without profile should return error",
 			scmpProfile: &v1.SeccompProfile{
 				Type: v1.SeccompProfileTypeLocalhost,
 			},
-			expectedProfile: v1.SeccompProfileRuntimeDefault,
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
 			description: "unknown type should return runtime/default",
@@ -335,7 +342,7 @@ func TestFieldProfileDefaultSeccomp(t *testing.T) {
 			description: "SeccompProfileTypeLocalhost should return localhost",
 			scmpProfile: &v1.SeccompProfile{
 				Type:             v1.SeccompProfileTypeLocalhost,
-				LocalhostProfile: utilpointer.StringPtr("profile.json"),
+				LocalhostProfile: utilpointer.String("profile.json"),
 			},
 			rootPath:        "/test/",
 			expectedProfile: "localhost//test/profile.json",
@@ -343,8 +350,13 @@ func TestFieldProfileDefaultSeccomp(t *testing.T) {
 	}
 
 	for i, test := range tests {
-		seccompProfile := fieldProfile(test.scmpProfile, test.rootPath, true)
-		assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		seccompProfile, err := fieldProfile(test.scmpProfile, test.rootPath, true)
+		if test.expectedError != "" {
+			assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+		} else {
+			assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+			assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		}
 	}
 }
 
@@ -359,6 +371,7 @@ func TestGetSeccompProfilePath(t *testing.T) {
 		containerSc     *v1.SecurityContext
 		containerName   string
 		expectedProfile string
+		expectedError   string
 	}{
 		{
 			description:     "no seccomp should return empty",
@@ -369,91 +382,6 @@ func TestGetSeccompProfilePath(t *testing.T) {
 			containerName:   "container1",
 			expectedProfile: "",
 		},
-		{
-			description: "annotations: pod runtime/default seccomp profile should return runtime/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
-			},
-			expectedProfile: "runtime/default",
-		},
-		{
-			description: "annotations: pod docker/default seccomp profile should return docker/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
-			},
-			expectedProfile: "docker/default",
-		},
-		{
-			description: "annotations: pod runtime/default seccomp profile with containerName should return runtime/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
-			},
-			containerName:   "container1",
-			expectedProfile: "runtime/default",
-		},
-		{
-			description: "annotations: pod docker/default seccomp profile with containerName should return docker/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
-			},
-			containerName:   "container1",
-			expectedProfile: "docker/default",
-		},
-		{
-			description: "annotations: pod unconfined seccomp profile should return unconfined",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
-			},
-			expectedProfile: "unconfined",
-		},
-		{
-			description: "annotations: pod unconfined seccomp profile with containerName should return unconfined",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
-			},
-			containerName:   "container1",
-			expectedProfile: "unconfined",
-		},
-		{
-			description: "annotations: pod localhost seccomp profile should return local profile path",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: "localhost/chmod.json",
-			},
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: pod localhost seccomp profile with containerName should return local profile path",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: "localhost/chmod.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: container localhost seccomp profile with containerName should return local profile path",
-			annotation: map[string]string{
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: container localhost seccomp profile should override pod profile",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey:                            v1.SeccompProfileNameUnconfined,
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: container localhost seccomp profile with unmatched containerName should return empty",
-			annotation: map[string]string{
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
-			},
-			containerName:   "container2",
-			expectedProfile: "",
-		},
 		{
 			description:     "pod seccomp profile set to unconfined returns unconfined",
 			podSc:           &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeUnconfined}},
@@ -480,14 +408,14 @@ func TestGetSeccompProfilePath(t *testing.T) {
 			expectedProfile: seccompLocalhostPath("filename"),
 		},
 		{
-			description:     "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns empty",
-			podSc:           &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: "",
+			description:   "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			podSc:         &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
-			description:     "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns empty",
-			containerSc:     &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: "",
+			description:   "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			containerSc:   &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
 			description:     "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -500,41 +428,16 @@ func TestGetSeccompProfilePath(t *testing.T) {
 			containerSc:     &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault}},
 			expectedProfile: "runtime/default",
 		},
-		{
-			description: "prioritise container field over container annotation, pod field and pod annotation",
-			podSc:       &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
-			containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-cont-profile.json")}},
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey:                            "localhost/annota-pod-profile.json",
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("field-cont-profile.json"),
-		},
-		{
-			description: "prioritise container annotation over pod field",
-			podSc:       &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey:                            "localhost/annota-pod-profile.json",
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("annota-cont-profile.json"),
-		},
-		{
-			description: "prioritise pod field over pod annotation",
-			podSc:       &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("field-pod-profile.json"),
-		},
 	}
 
 	for i, test := range tests {
-		seccompProfile := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, false)
-		assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		seccompProfile, err := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, false)
+		if test.expectedError != "" {
+			assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+		} else {
+			assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+			assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		}
 	}
 }
 
@@ -549,6 +452,7 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
 		containerSc     *v1.SecurityContext
 		containerName   string
 		expectedProfile string
+		expectedError   string
 	}{
 		{
 			description:     "no seccomp should return runtime/default",
@@ -559,91 +463,6 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
 			containerName:   "container1",
 			expectedProfile: v1.SeccompProfileRuntimeDefault,
 		},
-		{
-			description: "annotations: pod runtime/default seccomp profile should return runtime/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
-			},
-			expectedProfile: v1.SeccompProfileRuntimeDefault,
-		},
-		{
-			description: "annotations: pod docker/default seccomp profile should return docker/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
-			},
-			expectedProfile: "docker/default",
-		},
-		{
-			description: "annotations: pod runtime/default seccomp profile with containerName should return runtime/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
-			},
-			containerName:   "container1",
-			expectedProfile: v1.SeccompProfileRuntimeDefault,
-		},
-		{
-			description: "annotations: pod docker/default seccomp profile with containerName should return docker/default",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
-			},
-			containerName:   "container1",
-			expectedProfile: "docker/default",
-		},
-		{
-			description: "annotations: pod unconfined seccomp profile should return unconfined",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
-			},
-			expectedProfile: "unconfined",
-		},
-		{
-			description: "annotations: pod unconfined seccomp profile with containerName should return unconfined",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
-			},
-			containerName:   "container1",
-			expectedProfile: "unconfined",
-		},
-		{
-			description: "annotations: pod localhost seccomp profile should return local profile path",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: "localhost/chmod.json",
-			},
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: pod localhost seccomp profile with containerName should return local profile path",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: "localhost/chmod.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: container localhost seccomp profile with containerName should return local profile path",
-			annotation: map[string]string{
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: container localhost seccomp profile should override pod profile",
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey:                            v1.SeccompProfileNameUnconfined,
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("chmod.json"),
-		},
-		{
-			description: "annotations: container localhost seccomp profile with unmatched containerName should return runtime/default",
-			annotation: map[string]string{
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
-			},
-			containerName:   "container2",
-			expectedProfile: v1.SeccompProfileRuntimeDefault,
-		},
 		{
 			description:     "pod seccomp profile set to unconfined returns unconfined",
 			podSc:           &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeUnconfined}},
@@ -670,14 +489,14 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
 			expectedProfile: seccompLocalhostPath("filename"),
 		},
 		{
-			description:     "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns runtime/default",
-			podSc:           &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: v1.SeccompProfileRuntimeDefault,
+			description:   "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			podSc:         &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
-			description:     "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns runtime/default",
-			containerSc:     &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: v1.SeccompProfileRuntimeDefault,
+			description:   "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			containerSc:   &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
 			description:     "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -690,41 +509,16 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
 			containerSc:     &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault}},
 			expectedProfile: "runtime/default",
 		},
-		{
-			description: "prioritise container field over container annotation, pod field and pod annotation",
-			podSc:       &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
-			containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-cont-profile.json")}},
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey:                            "localhost/annota-pod-profile.json",
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("field-cont-profile.json"),
-		},
-		{
-			description: "prioritise container annotation over pod field",
-			podSc:       &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey:                            "localhost/annota-pod-profile.json",
-				v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("annota-cont-profile.json"),
-		},
-		{
-			description: "prioritise pod field over pod annotation",
-			podSc:       &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
-			annotation: map[string]string{
-				v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
-			},
-			containerName:   "container1",
-			expectedProfile: seccompLocalhostPath("field-pod-profile.json"),
-		},
 	}
 
 	for i, test := range tests {
-		seccompProfile := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, true)
-		assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		seccompProfile, err := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, true)
+		if test.expectedError != "" {
+			assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+		} else {
+			assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+			assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		}
 	}
 }
 
@@ -747,6 +541,7 @@ func TestGetSeccompProfile(t *testing.T) {
 		containerSc     *v1.SecurityContext
 		containerName   string
 		expectedProfile *runtimeapi.SecurityProfile
+		expectedError   string
 	}{
 		{
 			description:     "no seccomp should return unconfined",
@@ -781,14 +576,14 @@ func TestGetSeccompProfile(t *testing.T) {
 			},
 		},
 		{
-			description:     "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
-			podSc:           &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: unconfinedProfile,
+			description:   "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			podSc:         &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
-			description:     "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
-			containerSc:     &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: unconfinedProfile,
+			description:   "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			containerSc:   &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
 			description: "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -817,8 +612,13 @@ func TestGetSeccompProfile(t *testing.T) {
 	}
 
 	for i, test := range tests {
-		seccompProfile := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, false)
-		assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		seccompProfile, err := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, false)
+		if test.expectedError != "" {
+			assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+		} else {
+			assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+			assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		}
 	}
 }
 
@@ -841,6 +641,7 @@ func TestGetSeccompProfileDefaultSeccomp(t *testing.T) {
 		containerSc     *v1.SecurityContext
 		containerName   string
 		expectedProfile *runtimeapi.SecurityProfile
+		expectedError   string
 	}{
 		{
 			description:     "no seccomp should return RuntimeDefault",
@@ -875,14 +676,14 @@ func TestGetSeccompProfileDefaultSeccomp(t *testing.T) {
 			},
 		},
 		{
-			description:     "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
-			podSc:           &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: unconfinedProfile,
+			description:   "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			podSc:         &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
-			description:     "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
-			containerSc:     &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
-			expectedProfile: unconfinedProfile,
+			description:   "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+			containerSc:   &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+			expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
 		},
 		{
 			description: "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -911,8 +712,13 @@ func TestGetSeccompProfileDefaultSeccomp(t *testing.T) {
 	}
 
 	for i, test := range tests {
-		seccompProfile := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, true)
-		assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		seccompProfile, err := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, true)
+		if test.expectedError != "" {
+			assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+		} else {
+			assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+			assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+		}
 	}
 }
 
diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go b/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go
index 25917803b1c..1e9a2377b51 100644
--- a/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go
+++ b/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go
@@ -45,15 +45,23 @@ func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config
 		libcontainercgroups.IsCgroup2UnifiedMode() {
 		enforceMemoryQoS = true
 	}
-	config.Linux = m.generateLinuxContainerConfig(container, pod, uid, username, nsTarget, enforceMemoryQoS)
+	cl, err := m.generateLinuxContainerConfig(container, pod, uid, username, nsTarget, enforceMemoryQoS)
+	if err != nil {
+		return err
+	}
+	config.Linux = cl
 	return nil
 }
 
 // generateLinuxContainerConfig generates linux container config for kubelet runtime v1.
-func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string, nsTarget *kubecontainer.ContainerID, enforceMemoryQoS bool) *runtimeapi.LinuxContainerConfig {
+func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string, nsTarget *kubecontainer.ContainerID, enforceMemoryQoS bool) (*runtimeapi.LinuxContainerConfig, error) {
+	sc, err := m.determineEffectiveSecurityContext(pod, container, uid, username)
+	if err != nil {
+		return nil, err
+	}
 	lc := &runtimeapi.LinuxContainerConfig{
 		Resources:       &runtimeapi.LinuxContainerResources{},
-		SecurityContext: m.determineEffectiveSecurityContext(pod, container, uid, username),
+		SecurityContext: sc,
 	}
 
 	if nsTarget != nil && lc.SecurityContext.NamespaceOptions.Pid == runtimeapi.NamespaceMode_CONTAINER {
@@ -124,7 +132,7 @@ func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.C
 		}
 	}
 
-	return lc
+	return lc, nil
 }
 
 // calculateLinuxResources will create the linuxContainerResources type based on the provided CPU and memory resource requests, limits
diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go b/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go
index 29d0bbfc9b4..838ecf8c6f5 100644
--- a/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go
+++ b/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go
@@ -47,6 +47,8 @@ func makeExpectedConfig(m *kubeGenericRuntimeManager, pod *v1.Pod, containerInde
 	restartCountUint32 := uint32(restartCount)
 	envs := make([]*runtimeapi.KeyValue, len(opts.Envs))
 
+	l, _ := m.generateLinuxContainerConfig(container, pod, new(int64), "", nil, enforceMemoryQoS)
+
 	expectedConfig := &runtimeapi.ContainerConfig{
 		Metadata: &runtimeapi.ContainerMetadata{
 			Name:    container.Name,
@@ -64,7 +66,7 @@ func makeExpectedConfig(m *kubeGenericRuntimeManager, pod *v1.Pod, containerInde
 		Stdin:       container.Stdin,
 		StdinOnce:   container.StdinOnce,
 		Tty:         container.TTY,
-		Linux:       m.generateLinuxContainerConfig(container, pod, new(int64), "", nil, enforceMemoryQoS),
+		Linux:       l,
 		Envs:        envs,
 	}
 	return expectedConfig
@@ -215,7 +217,8 @@ func TestGenerateLinuxContainerConfigResources(t *testing.T) {
 			},
 		}
 
-		linuxConfig := m.generateLinuxContainerConfig(&pod.Spec.Containers[0], pod, new(int64), "", nil, false)
+		linuxConfig, err := m.generateLinuxContainerConfig(&pod.Spec.Containers[0], pod, new(int64), "", nil, false)
+		assert.NoError(t, err)
 		assert.Equal(t, test.expected.CpuPeriod, linuxConfig.GetResources().CpuPeriod, test.name)
 		assert.Equal(t, test.expected.CpuQuota, linuxConfig.GetResources().CpuQuota, test.name)
 		assert.Equal(t, test.expected.CpuShares, linuxConfig.GetResources().CpuShares, test.name)
@@ -329,6 +332,8 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
 		memoryLow       int64
 		memoryHigh      int64
 	}
+	l1, _ := m.generateLinuxContainerConfig(&pod1.Spec.Containers[0], pod1, new(int64), "", nil, true)
+	l2, _ := m.generateLinuxContainerConfig(&pod2.Spec.Containers[0], pod2, new(int64), "", nil, true)
 	tests := []struct {
 		name     string
 		pod      *v1.Pod
@@ -338,7 +343,7 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
 			name: "Request128MBLimit256MB",
 			pod:  pod1,
 			expected: &expectedResult{
-				m.generateLinuxContainerConfig(&pod1.Spec.Containers[0], pod1, new(int64), "", nil, true),
+				l1,
 				128 * 1024 * 1024,
 				int64(float64(256*1024*1024) * m.memoryThrottlingFactor),
 			},
@@ -347,7 +352,7 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
 			name: "Request128MBWithoutLimit",
 			pod:  pod2,
 			expected: &expectedResult{
-				m.generateLinuxContainerConfig(&pod2.Spec.Containers[0], pod2, new(int64), "", nil, true),
+				l2,
 				128 * 1024 * 1024,
 				int64(pod2MemoryHigh),
 			},
@@ -355,7 +360,8 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		linuxConfig := m.generateLinuxContainerConfig(&test.pod.Spec.Containers[0], test.pod, new(int64), "", nil, true)
+		linuxConfig, err := m.generateLinuxContainerConfig(&test.pod.Spec.Containers[0], test.pod, new(int64), "", nil, true)
+		assert.NoError(t, err)
 		assert.Equal(t, test.expected.containerConfig, linuxConfig, test.name)
 		assert.Equal(t, linuxConfig.GetResources().GetUnified()["memory.min"], strconv.FormatInt(test.expected.memoryLow, 10), test.name)
 		assert.Equal(t, linuxConfig.GetResources().GetUnified()["memory.high"], strconv.FormatInt(test.expected.memoryHigh, 10), test.name)
@@ -578,7 +584,8 @@ func TestGenerateLinuxContainerConfigNamespaces(t *testing.T) {
 		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {
-			got := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", tc.target, false)
+			got, err := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", tc.target, false)
+			assert.NoError(t, err)
 			if diff := cmp.Diff(tc.want, got.SecurityContext.NamespaceOptions); diff != "" {
 				t.Errorf("%v: diff (-want +got):\n%v", t.Name(), diff)
 			}
@@ -669,7 +676,8 @@ func TestGenerateLinuxContainerConfigSwap(t *testing.T) {
 	} {
 		t.Run(tc.name, func(t *testing.T) {
 			m.memorySwapBehavior = tc.swapSetting
-			actual := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", nil, false)
+			actual, err := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", nil, false)
+			assert.NoError(t, err)
 			assert.Equal(t, tc.expected, actual.Resources.MemorySwapLimitInBytes, "memory swap config for %s", tc.name)
 		})
 	}
diff --git a/pkg/kubelet/kuberuntime/security_context.go b/pkg/kubelet/kuberuntime/security_context.go
index c9d33e44305..3b575c8e974 100644
--- a/pkg/kubelet/kuberuntime/security_context.go
+++ b/pkg/kubelet/kuberuntime/security_context.go
@@ -24,7 +24,7 @@ import (
 )
 
 // determineEffectiveSecurityContext gets container's security context from v1.Pod and v1.Container.
-func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container, uid *int64, username string) *runtimeapi.LinuxContainerSecurityContext {
+func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container, uid *int64, username string) (*runtimeapi.LinuxContainerSecurityContext, error) {
 	effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
 	synthesized := convertToRuntimeSecurityContext(effectiveSc)
 	if synthesized == nil {
@@ -36,9 +36,16 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po
 
 	// TODO: Deprecated, remove after we switch to Seccomp field
 	// set SeccompProfilePath.
-	synthesized.SeccompProfilePath = m.getSeccompProfilePath(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+	var err error
+	synthesized.SeccompProfilePath, err = m.getSeccompProfilePath(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+	if err != nil {
+		return nil, err
+	}
 
-	synthesized.Seccomp = m.getSeccompProfile(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+	synthesized.Seccomp, err = m.getSeccompProfile(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+	if err != nil {
+		return nil, err
+	}
 
 	// set ApparmorProfile.
 	synthesized.ApparmorProfile = apparmor.GetProfileNameFromPodAnnotations(pod.Annotations, container.Name)
@@ -74,7 +81,7 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po
 	synthesized.MaskedPaths = securitycontext.ConvertToRuntimeMaskedPaths(effectiveSc.ProcMount)
 	synthesized.ReadonlyPaths = securitycontext.ConvertToRuntimeReadonlyPaths(effectiveSc.ProcMount)
 
-	return synthesized
+	return synthesized, nil
 }
 
 // convertToRuntimeSecurityContext converts v1.SecurityContext to runtimeapi.SecurityContext.
-- 
2.25.1

