File: prctl.py

package info (click to toggle)
python-prctl 1.7-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 176 kB
  • sloc: ansic: 705; python: 530; makefile: 80
file content (185 lines) | stat: -rw-r--r-- 6,960 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# python-pctrl -- python interface to the prctl function
# (c)2010-2018 Dennis Kaarsemaker <dennis@kaarsemaker.net>
# See COPYING for licensing details

import _prctl # The C interface
import sys

# Python 3.x compatibility
if sys.version_info[0] >= 3:
    basestring = str

# Code generation functions
def prctl_wrapper(option):
    def call_prctl(arg=0):
        return _prctl.prctl(option, arg)
    return call_prctl

def capb_wrapper(cap):
    def getter(self):
        return _prctl.prctl(_prctl.PR_CAPBSET_READ, cap)
    def setter(self, value):
        if value:
            raise ValueError("Can only drop capabilities from the bounding set, not add new ones")
        _prctl.prctl(_prctl.PR_CAPBSET_DROP, cap)
    return property(getter, setter)

def cap_wrapper(cap):
    def getter(self):
        return get_caps((cap, self.flag))[self.flag][cap]
    def setter(self, val):
        set_caps((cap, self.flag, val))
    return property(getter, setter)

def sec_wrapper(bit):
    def getter(self):
        return bool(_prctl.prctl(_prctl.PR_GET_SECUREBITS) & bit)
    def setter(self, value):
        bits = _prctl.prctl(_prctl.PR_GET_SECUREBITS)
        if value:
            bits |= bit
        else:
            bits &= ~(bit)
        _prctl.prctl(_prctl.PR_SET_SECUREBITS, bits)
    return property(getter, setter)

# Wrap the capabilities, capability bounding set and securebits in an object
_ALL_FLAG_NAMES  = ('CAP_EFFECTIVE', 'CAP_INHERITABLE', 'CAP_PERMITTED')
_ALL_CAP_NAMES = tuple(x for x in dir(_prctl) if x.startswith('CAP_') and x not in _ALL_FLAG_NAMES)
ALL_FLAG_NAMES  = list(x[4:].lower() for x in _ALL_FLAG_NAMES)
ALL_CAP_NAMES  = list(x[4:].lower() for x in _ALL_CAP_NAMES)
ALL_CAPS = tuple(getattr(_prctl,x) for x in _ALL_CAP_NAMES)
ALL_FLAGS = tuple(getattr(_prctl,x) for x in _ALL_FLAG_NAMES)

class Capbset(object):
    __slots__ = ALL_CAP_NAMES
    def __init__(self):
        for name in _ALL_CAP_NAMES:
            friendly_name = name[4:].lower()
            setattr(self.__class__, friendly_name, capb_wrapper(getattr(_prctl, name)))

    def drop(self, *caps):
        for cap in _parse_caps_simple(caps):
            _prctl.prctl(_prctl.PR_CAPBSET_DROP, cap)

    def limit(self, *caps):
        for cap in [x for x in ALL_CAPS if x not in _parse_caps_simple(caps)]:
            _prctl.prctl(_prctl.PR_CAPBSET_DROP, cap)

capbset = Capbset()

class Capset(object):
    __slots__ = ALL_CAP_NAMES + ['flag']
    def __init__(self, flag):
        self.flag = flag
        for name in _ALL_CAP_NAMES:
            friendly_name = name[4:].lower()
            setattr(self.__class__, friendly_name, cap_wrapper(getattr(_prctl, name)))

    def drop(self, *caps):
        set_caps((_parse_caps_simple(caps), self.flag, False))

    def limit(self, *caps):
        set_caps(([x for x in ALL_CAPS if x not in _parse_caps_simple(caps)], self.flag, False))

cap_effective = Capset(_prctl.CAP_EFFECTIVE)
cap_inheritable = Capset(_prctl.CAP_INHERITABLE)
cap_permitted = Capset(_prctl.CAP_PERMITTED)

class Securebits(object):
    __slots__ = [name[7:].lower() for name in dir(_prctl) if name.startswith('SECBIT_')]
    def __init__(self):
        for name in dir(_prctl):
            if name.startswith('SECBIT_'):
                friendly_name = name[7:].lower()
                setattr(self.__class__, friendly_name, sec_wrapper(getattr(_prctl, name)))

securebits = Securebits()

# Copy constants from _prctl and generate the functions
self = sys.modules['prctl']
for name in dir(_prctl):
    if name.startswith('PR_GET') or name.startswith('PR_SET') and name != 'PR_SET_PTRACER_ANY' or name.startswith('PR_CAPBSET'):
        # Generate a function for this option
        val = getattr(_prctl, name)
        friendly_name = name.lower()[3:]
        setattr(self, friendly_name, prctl_wrapper(val))

    elif name.startswith('PR_'):
        # Add the argument constants without PR_ prefix
        setattr(self, name[3:], getattr(_prctl, name))

    elif name.startswith('CAP_') or name.startswith('SECBIT_') or name.startswith('SECURE_'):
        # Add CAP_*/SECBIT_*/SECURE_* constants verbatim. You shouldn't use them anyway,
        # use the capbset/securebits object
        setattr(self, name, getattr(_prctl, name))

def _parse_caps_simple(caps):
    ret = []
    for cap in caps:
        if isinstance(cap, basestring):
            if 'CAP_' + cap.upper() in _ALL_CAP_NAMES:
                cap = 'CAP_' + cap.upper()
            elif cap not in _ALL_CAP_NAMES:
                raise ValueError("Unknown capability: %s" % cap)
            cap = getattr(_prctl, cap)
        elif cap not in ALL_CAPS:
            raise ValueError("Unknown capability: %s" % str(cap))
        ret.append(cap)
    return ret

def _parse_caps(has_value, *args):
    if has_value:
        new_args = {(_prctl.CAP_PERMITTED,True): [],
                    (_prctl.CAP_INHERITABLE,True): [],
                    (_prctl.CAP_EFFECTIVE,True): [],
                    (_prctl.CAP_PERMITTED,False): [],
                    (_prctl.CAP_INHERITABLE,False): [],
                    (_prctl.CAP_EFFECTIVE,False): []}
    else:
        new_args = {_prctl.CAP_PERMITTED: [],
                    _prctl.CAP_INHERITABLE: [],
                    _prctl.CAP_EFFECTIVE: []}
    for arg in args:
        if has_value:
            caps, flags, value = arg
        else:
            caps, flags = arg
        # Accepted format: (cap|[cap,...], flag|[flag,...])
        if not (hasattr(caps, '__iter__') or hasattr(caps, '__getitem__')):
            caps = [caps]
        caps = _parse_caps_simple(caps)
        if not (hasattr(flags, '__iter__') or hasattr(flags, '__getitem__')):
            flags = [flags]
        for cap in caps:
            for flag in flags:
                if has_value:
                    new_args[(flag,value)].append(cap)
                else:
                    new_args[flag].append(cap)
    if has_value:
        et = list(set(new_args[(_prctl.CAP_EFFECTIVE,True)]))
        pt = list(set(new_args[(_prctl.CAP_PERMITTED,True)]))
        it = list(set(new_args[(_prctl.CAP_INHERITABLE,True)]))
        ef = list(set(new_args[(_prctl.CAP_EFFECTIVE,False)]))
        pf = list(set(new_args[(_prctl.CAP_PERMITTED,False)]))
        if_ = list(set(new_args[(_prctl.CAP_INHERITABLE,False)]))
        return (et, pt, it, ef, pf, if_)
    else:
        e = list(set(new_args[_prctl.CAP_EFFECTIVE]))
        p = list(set(new_args[_prctl.CAP_PERMITTED]))
        i = list(set(new_args[_prctl.CAP_INHERITABLE]))
        return (e, p, i)

def get_caps(*args):
    return _prctl.get_caps(*_parse_caps(False, *args))

def set_caps(*args):
    return _prctl.set_caps(*_parse_caps(True, *args))

# Functions copied directly, not part of the prctl interface
set_proctitle = _prctl.set_proctitle

# Delete the init-only things
del self, friendly_name, name, prctl_wrapper, cap_wrapper, capb_wrapper, sec_wrapper
del Capbset, Capset, Securebits, sys, val