Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/scheduler/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (h *webhook) Handle(_ context.Context, req admission.Request) admission.Res
if ctr.SecurityContext != nil {
if ctr.SecurityContext.Privileged != nil && *ctr.SecurityContext.Privileged {
klog.Warningf(template+" - Denying admission as container %s is privileged", pod.Namespace, pod.Name, pod.UID, c.Name)
continue
return admission.Denied("privileged containers are not allowed")
Comment on lines 74 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)pkg/scheduler/(webhook\.go|webhook_test\.go)$|hack/.import-aliases' || true

echo "== webhook outline =="
ast-grep outline pkg/scheduler/webhook.go || true

echo "== relevant webhook.go =="
sed -n '1,130p' pkg/scheduler/webhook.go

echo "== relevant webhook_test.go =="
sed -n '530,655p' pkg/scheduler/webhook_test.go

echo "== privilege references =="
rg -n -C 3 "privilege|Privileged|InitContainers|EphemeralContainers|SchedulerName|Allowed|Denied" pkg/scheduler/webhook.go pkg/scheduler/webhook_test.go

Repository: Project-HAMi/HAMi

Length of output: 26556


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== inspect init-container tests around earlier scheduler-different tests =="
sed -n '160,245p' pkg/scheduler/webhook_test.go

echo "== behavioral source probe: does Handle return Allowed before privileged check under preassigned scheduler? =="
python3 - <<'PY'
from pathlib import Path
text = Path('pkg/scheduler/webhook.go').read_text()
checks = {
    'scheduler_allow_before_privileged_loop': text.index('return admission.Allowed("pod already has different scheduler assigned")') < text.index('// Denying admission as container %s is privileged'),
    'only_one_privileged_loop_in_containers': text.count('for idx, ctr := range pod.Spec.Containers') == 1,
    'contains_initcontainers_loop': 'for idx, ctr := range pod.Spec.InitContainers' in text,
    'contains_ephemeralcontainers_loop': 'for idx, ctr := range pod.Spec.EphemeralContainers' in text,
}
for k, v in checks.items():
    print(f'{k}={v}')
print('privileged check appears only inside first Containers loop:', 'Privileged' in text)
print('allowed response in Handle:', 'admission.Allowed' in text)
PY

Repository: Project-HAMi/HAMi

Length of output: 2573


Check privileged containers before allowing preassigned-scheduler pods and cover init/ephemeral containers.

A pod with SchedulerName set to a non-default scheduler returns admission.Allowed before reaching the privileged container deny path, and the validation only scans Containers. Move the privileged check ahead of the scheduler-name allow path and include InitContainers and EphemeralContainers; add regression tests for privileged init/ephemeral containers and a privileged pod with a different preassigned scheduler.

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 75-75: A log/format call (log.Print/Printf/Println, the Fatal/Panic variants, fmt.Sprintf, or a structured logger's Info/Warn/Error/Debug method) is given a message built by concatenating a string literal with a non-literal value such as request data. Unsanitized, attacker-controlled input written to logs enables log forging / CRLF injection: an attacker can inject newlines to spoof log entries or break log parsers. Do not concatenate raw input into the log message; pass it as a separate structured field/argument (e.g. 'log.Printf("user: %s", user)' or 'logger.Info("login", "user", user)') and strip or escape newline characters first.
Context: klog.Warningf(template+" - Denying admission as container %s is privileged", pod.Namespace, pod.Name, pod.UID, c.Name)
Note: [CWE-117] Improper Output Neutralization for Logs.

(log-injection-request-data-concat-go)

📍 Affects 2 files
  • pkg/scheduler/webhook.go#L74-L77 (this comment)
  • pkg/scheduler/webhook_test.go#L575-L630
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/scheduler/webhook.go` around lines 74 - 77, The privileged-container
validation in pkg/scheduler/webhook.go around the existing SecurityContext check
must run before the preassigned SchedulerName allow path, and must inspect
Containers, InitContainers, and EphemeralContainers. Update the relevant
admission logic while preserving denial for any privileged container, then add
regression coverage in pkg/scheduler/webhook_test.go around the existing
scheduler admission tests for privileged init containers, privileged ephemeral
containers, and privileged pods using a non-default scheduler.

}
}
for _, val := range device.GetDevices() {
Expand Down
85 changes: 85 additions & 0 deletions pkg/scheduler/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,91 @@ func TestEmptyContainersDenied(t *testing.T) {
}
}

func TestPrivilegedContainerDeniedAdmission(t *testing.T) {
prevSchedulerName := config.SchedulerName
prevForceOverwrite := config.ForceOverwriteDefaultScheduler
t.Cleanup(func() {
config.SchedulerName = prevSchedulerName
config.ForceOverwriteDefaultScheduler = prevForceOverwrite
})

config.SchedulerName = "hami-scheduler"
config.ForceOverwriteDefaultScheduler = true

sConfig := &config.Config{
NvidiaConfig: nvidia.NvidiaConfig{
ResourceCountName: "hami.io/gpu",
ResourceMemoryName: "hami.io/gpumem",
ResourceMemoryPercentageName: "hami.io/gpumem-percentage",
ResourceCoreName: "hami.io/gpucores",
DefaultMemory: 0,
DefaultCores: 0,
DefaultGPUNum: 1,
},
}

if err := config.InitDevicesWithConfig(sConfig); err != nil {
klog.Fatalf("Failed to initialize devices with config: %v", err)
}

privileged := true
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "privileged-gpu-mixed",
Namespace: "default",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "privileged-sidecar",
Image: "busybox",
SecurityContext: &corev1.SecurityContext{
Privileged: &privileged,
},
},
{
Name: "gpu-workload",
Image: "busybox",
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
"hami.io/gpu": resource.MustParse("1"),
},
},
},
},
},
}

scheme := runtime.NewScheme()
corev1.AddToScheme(scheme)
codec := serializer.NewCodecFactory(scheme).LegacyCodec(corev1.SchemeGroupVersion)
podBytes, err := runtime.Encode(codec, pod)
if err != nil {
t.Fatalf("Error encoding pod: %v", err)
}

req := admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
UID: "privileged-gpu-mixed-uid",
Namespace: "default",
Name: "privileged-gpu-mixed",
Object: runtime.RawExtension{
Raw: podBytes,
},
},
}

wh, err := NewWebHook()
if err != nil {
t.Fatalf("Error creating WebHook: %v", err)
}

resp := wh.Handle(context.Background(), req)
if resp.Allowed {
t.Fatalf("Expected pod with privileged container to be denied, but got allowed")
}
}

func TestSchedulerNameEmptyNoOverwrite(t *testing.T) {
prevSchedulerName := config.SchedulerName
prevForceOverwrite := config.ForceOverwriteDefaultScheduler
Expand Down
Loading