github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/pkg/user/uid_range.go (about) 1 // Copyright 2015 The rkt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // For how the uidshift and uidcount are generated please check: 16 // http://cgit.freedesktop.org/systemd/systemd/commit/?id=03cfe0d51499e86b1573d1 17 18 package user 19 20 import ( 21 "errors" 22 "fmt" 23 "math" 24 "math/rand" 25 "time" 26 27 "github.com/hashicorp/errwrap" 28 ) 29 30 const DefaultRangeCount = 0x10000 31 32 // A UidRange structure used to set uidshift and its range. 33 type UidRange struct { 34 Shift uint32 35 Count uint32 36 } 37 38 func generateUidShift() uint32 { 39 rand.Seed(time.Now().UnixNano()) 40 // we force the MSB to 0 because devpts parses the uid,gid options as int 41 // instead of as uint. 42 // http://lxr.free-electrons.com/source/fs/devpts/inode.c?v=4.1#L189 43 // systemd issue: https://github.com/systemd/systemd/issues/956 44 n := rand.Intn(0x7FFF) + 1 45 uidShift := uint32(n << 16) 46 47 return uidShift 48 } 49 50 func NewBlankUidRange() *UidRange { 51 return &UidRange{ 52 Shift: 0, 53 Count: 0} 54 } 55 56 func (r *UidRange) SetRandomUidRange(uidCount uint32) { 57 uidShift := generateUidShift() 58 r.Shift = uidShift 59 r.Count = uidCount 60 } 61 62 func (r *UidRange) ShiftRange(uid uint32, gid uint32) (uint32, uint32, error) { 63 if r.Count > 0 && (uid >= r.Count || gid >= r.Count) { 64 return 0, 0, fmt.Errorf("uid %d or gid %d are out of range %d", uid, gid, r.Count) 65 } 66 if math.MaxUint32-r.Shift < uid || math.MaxUint32-r.Shift < gid { 67 return 0, 0, fmt.Errorf("uid or gid are out of range %d after shifting", uint32(math.MaxUint32)) 68 } 69 return uid + r.Shift, gid + r.Shift, nil 70 } 71 72 func (r *UidRange) UnshiftRange(uid, gid uint32) (uint32, uint32, error) { 73 if uid < r.Shift || gid < r.Shift || (r.Count > 0 && (uid >= r.Shift+r.Count || gid >= r.Shift+r.Count)) { 74 return 0, 0, fmt.Errorf("uid %d or gid %d are out of range %d after unshifting", uid, gid, r.Count) 75 } 76 return uid - r.Shift, gid - r.Shift, nil 77 } 78 79 func (r *UidRange) Serialize() []byte { 80 return []byte(fmt.Sprintf("%d:%d", r.Shift, r.Count)) 81 } 82 83 func (r *UidRange) Deserialize(uidRange []byte) error { 84 if len(uidRange) == 0 { 85 return nil 86 } 87 _, err := fmt.Sscanf(string(uidRange), "%d:%d", &r.Shift, &r.Count) 88 if err != nil { 89 return errwrap.Wrap(errors.New("error deserializing uid range"), err) 90 } 91 92 return nil 93 }