syscall_iterator.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/linux_seccomp.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace sandbox { 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint32_t SyscallIterator::Next() { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (done_) { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return num_; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t val; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |num_| has been initialized to 4000, which we assume is also MIN_SYSCALL. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is true for Mips O32 ABI. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(MIN_SYSCALL == __NR_Linux, min_syscall_should_be_4000); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |num_| has been initialized to 0, which we assume is also MIN_SYSCALL. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This true for supported architectures (Intel and ARM EABI). 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) COMPILE_ASSERT(MIN_SYSCALL == 0u, min_syscall_should_always_be_zero); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val = num_; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The syscall iterator always starts at zero. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If zero is not a valid system call, iterator first returns MIN_SYSCALL -1 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // before continuing to iterate. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_ == 0 && MIN_SYSCALL != num_) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_ = MIN_SYSCALL - 1; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on Intel architectures, but leaves room for private syscalls on ARM. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (num_ <= MAX_PUBLIC_SYSCALL) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (invalid_only_ && num_ < MAX_PUBLIC_SYSCALL) { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_ = MAX_PUBLIC_SYSCALL; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__arm__) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ARM EABI includes "ARM private" system calls starting at 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MIN_PRIVATE_SYSCALL, and a "ghost syscall private to the kernel" at 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MIN_GHOST_SYSCALL. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (num_ < MIN_PRIVATE_SYSCALL - 1) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_ = MIN_PRIVATE_SYSCALL - 1; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (num_ <= MAX_PRIVATE_SYSCALL) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (invalid_only_ && num_ < MAX_PRIVATE_SYSCALL) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_ = MAX_PRIVATE_SYSCALL; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (num_ < MIN_GHOST_SYSCALL - 1) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_ = MIN_GHOST_SYSCALL - 1; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (num_ <= MAX_SYSCALL) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (invalid_only_ && num_ < MAX_SYSCALL) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_ = MAX_SYSCALL; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BPF programs only ever operate on unsigned quantities. So, that's how 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we iterate; we return values from 0..0xFFFFFFFFu. But there are places, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // where the kernel might interpret system call numbers as signed 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // quantities, so the boundaries between signed and unsigned values are 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // potential problem cases. We want to explicitly return these values from 69 // our iterator. 70 } else if (num_ < 0x7FFFFFFFu) { 71 num_ = 0x7FFFFFFFu; 72 } else if (num_ < 0x80000000u) { 73 num_ = 0x80000000u; 74 } else if (num_ < 0xFFFFFFFFu) { 75 num_ = 0xFFFFFFFFu; 76 } 77 } while (invalid_only_ && IsValid(val)); 78 79 done_ |= val == 0xFFFFFFFFu; 80 return val; 81} 82 83bool SyscallIterator::IsValid(uint32_t num) { 84 uint32_t min_syscall = MIN_SYSCALL; 85 if (num >= min_syscall && num <= MAX_PUBLIC_SYSCALL) { 86 return true; 87 } 88 if (IsArmPrivate(num)) { 89 return true; 90 } 91 return false; 92} 93 94#if defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__)) 95bool SyscallIterator::IsArmPrivate(uint32_t num) { 96 return (num >= MIN_PRIVATE_SYSCALL && num <= MAX_PRIVATE_SYSCALL) || 97 (num >= MIN_GHOST_SYSCALL && num <= MAX_SYSCALL); 98} 99#else 100bool SyscallIterator::IsArmPrivate(uint32_t) { return false; } 101#endif 102 103} // namespace sandbox 104