Skip to content

Commit 4ab6405

Browse files
authored
Merge pull request #101 from bleggett/bleggett/fix-shift-caps-older
Fix bit shift bug in caps
2 parents 328198e + 7806a4e commit 4ab6405

1 file changed

Lines changed: 97 additions & 25 deletions

File tree

src/caps.rs

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,29 @@ fn capset(result: &CapInternalResult) -> anyhow::Result<()> {
355355
}
356356
}
357357

358+
fn cap_data_to_result(data: &[CapInternalData; 2]) -> CapResult {
359+
CapResult {
360+
effective: ((data[1].effective as u64) << 32) | data[0].effective as u64,
361+
permitted: ((data[1].permitted as u64) << 32) | data[0].permitted as u64,
362+
inheritable: ((data[1].inheritable as u64) << 32) | data[0].inheritable as u64,
363+
}
364+
}
365+
366+
fn cap_result_to_data(caps: &CapResult) -> [CapInternalData; 2] {
367+
[
368+
CapInternalData {
369+
effective: caps.effective as u32,
370+
permitted: caps.permitted as u32,
371+
inheritable: caps.inheritable as u32,
372+
},
373+
CapInternalData {
374+
effective: (caps.effective >> 32) as u32,
375+
permitted: (caps.permitted >> 32) as u32,
376+
inheritable: (caps.inheritable >> 32) as u32,
377+
},
378+
]
379+
}
380+
358381
pub fn get_caps() -> anyhow::Result<CapResult> {
359382
let pid = std::process::id() as i32;
360383
let mut iresult = CapInternalResult {
@@ -367,23 +390,14 @@ pub fn get_caps() -> anyhow::Result<CapResult> {
367390

368391
capget(&mut iresult)?;
369392

370-
let effective = ((iresult.data[0].effective as u64) << 32) | iresult.data[1].effective as u64;
371-
let permitted = ((iresult.data[0].permitted as u64) << 32) | iresult.data[1].permitted as u64;
372-
let inheritable =
373-
((iresult.data[0].inheritable as u64) << 32) | iresult.data[1].inheritable as u64;
374-
375-
let finalresult = CapResult {
376-
effective,
377-
permitted,
378-
inheritable,
379-
};
393+
let result = cap_data_to_result(&iresult.data);
380394

381395
debug!(
382-
"get capabilities of pid {}: eff={:x} perm={:x} inh={:?}",
383-
iresult.header.pid, effective, permitted, inheritable
396+
"get capabilities of pid {}: eff={:x} perm={:x} inh={:x}",
397+
iresult.header.pid, result.effective, result.permitted, result.inheritable
384398
);
385399

386-
Ok(finalresult)
400+
Ok(result)
387401
}
388402

389403
pub fn set_caps(caps: CapResult) -> anyhow::Result<()> {
@@ -399,18 +413,7 @@ pub fn set_caps(caps: CapResult) -> anyhow::Result<()> {
399413
version: _LINUX_CAPABILITY_VERSION_3,
400414
pid,
401415
},
402-
data: [
403-
CapInternalData {
404-
effective: (caps.effective >> 32) as u32,
405-
permitted: (caps.permitted >> 32) as u32,
406-
inheritable: (caps.inheritable >> 32) as u32,
407-
},
408-
CapInternalData {
409-
effective: caps.effective as u32,
410-
permitted: caps.permitted as u32,
411-
inheritable: caps.inheritable as u32,
412-
},
413-
],
416+
data: cap_result_to_data(&caps),
414417
};
415418

416419
capset(&iresult)?;
@@ -429,3 +432,72 @@ pub fn set_keep_caps() -> anyhow::Result<()> {
429432
Ok(())
430433
}
431434
}
435+
436+
#[cfg(test)]
437+
mod tests {
438+
use super::*;
439+
440+
#[test]
441+
fn test_cap_encoding_word_order() {
442+
// Low caps only (0-31): CAP_CHOWN=0, CAP_NET_RAW=13, CAP_SETFCAP=31
443+
let low_caps = CapabilityBit::raw_bits(&[
444+
CapabilityBit::Chown,
445+
CapabilityBit::NetRaw,
446+
CapabilityBit::Setfcap,
447+
]);
448+
let input = CapResult {
449+
effective: low_caps,
450+
permitted: low_caps,
451+
inheritable: low_caps,
452+
};
453+
let data = cap_result_to_data(&input);
454+
assert_eq!(
455+
data[0].effective, low_caps as u32,
456+
"data[0] must hold low 32 bits (caps 0-31)"
457+
);
458+
assert_eq!(
459+
data[1].effective, 0u32,
460+
"data[1] must be zero for low-only caps"
461+
);
462+
let rt = cap_data_to_result(&data);
463+
assert_eq!(rt.effective, low_caps);
464+
465+
// High caps only (32-63): CAP_MAC_OVERRIDE=32, CAP_CHECKPOINT_RESTORE=40
466+
let high_caps = CapabilityBit::raw_bits(&[
467+
CapabilityBit::MacOverride,
468+
CapabilityBit::CheckpointRestore,
469+
]);
470+
let input = CapResult {
471+
effective: high_caps,
472+
permitted: high_caps,
473+
inheritable: high_caps,
474+
};
475+
let data = cap_result_to_data(&input);
476+
assert_eq!(
477+
data[0].effective, 0u32,
478+
"data[0] must be zero for high-only caps"
479+
);
480+
assert_eq!(
481+
data[1].effective,
482+
(high_caps >> 32) as u32,
483+
"data[1] must hold high 32 bits (caps 32-63)"
484+
);
485+
let rt = cap_data_to_result(&data);
486+
assert_eq!(rt.effective, high_caps);
487+
488+
// All caps: bits 0-40
489+
let all_caps = CapabilityBit::raw_bits(CapabilityBit::ALL);
490+
let input = CapResult {
491+
effective: all_caps,
492+
permitted: all_caps,
493+
inheritable: all_caps,
494+
};
495+
let data = cap_result_to_data(&input);
496+
assert_eq!(data[0].effective, all_caps as u32);
497+
assert_eq!(data[1].effective, (all_caps >> 32) as u32);
498+
let rt = cap_data_to_result(&data);
499+
assert_eq!(rt.effective, all_caps);
500+
assert_eq!(rt.permitted, all_caps);
501+
assert_eq!(rt.inheritable, all_caps);
502+
}
503+
}

0 commit comments

Comments
 (0)