audit2why.c revision 56258807ea4b33cf3c7a1dbf1b574ab77c91f899
1/* Workaround for http://bugs.python.org/issue4835 */ 2#ifndef SIZEOF_SOCKET_T 3#define SIZEOF_SOCKET_T SIZEOF_INT 4#endif 5 6#include <Python.h> 7#include <unistd.h> 8#include <stdlib.h> 9#include <ctype.h> 10#include <errno.h> 11#include <getopt.h> 12#include <limits.h> 13#include <sepol/sepol.h> 14#include <sepol/policydb.h> 15#include <sepol/policydb/services.h> 16#include <selinux/selinux.h> 17 18#define UNKNOWN -1 19#define BADSCON -2 20#define BADTCON -3 21#define BADTCLASS -4 22#define BADPERM -5 23#define BADCOMPUTE -6 24#define NOPOLICY -7 25#define ALLOW 0 26#define DONTAUDIT 1 27#define TERULE 2 28#define BOOLEAN 3 29#define CONSTRAINT 4 30#define RBAC 5 31 32struct boolean_t { 33 char *name; 34 int active; 35}; 36 37static struct boolean_t **boollist = NULL; 38static int boolcnt = 0; 39 40struct avc_t { 41 sepol_handle_t *handle; 42 sepol_policydb_t *policydb; 43 sepol_security_id_t ssid; 44 sepol_security_id_t tsid; 45 sepol_security_class_t tclass; 46 sepol_access_vector_t av; 47}; 48 49static struct avc_t *avc = NULL; 50 51static sidtab_t sidtab; 52 53static int load_booleans(const sepol_bool_t * boolean, 54 void *arg __attribute__ ((__unused__))) 55{ 56 boollist[boolcnt] = malloc(sizeof(struct boolean_t)); 57 boollist[boolcnt]->name = strdup(sepol_bool_get_name(boolean)); 58 boollist[boolcnt]->active = sepol_bool_get_value(boolean); 59 boolcnt++; 60 return 0; 61} 62 63static int check_booleans(struct boolean_t **bools) 64{ 65 char errormsg[PATH_MAX]; 66 struct sepol_av_decision avd; 67 unsigned int reason; 68 int rc; 69 int i; 70 sepol_bool_key_t *key = NULL; 71 sepol_bool_t *boolean = NULL; 72 int fcnt = 0; 73 int *foundlist = calloc(boolcnt, sizeof(int)); 74 if (!foundlist) { 75 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 76 return fcnt; 77 } 78 for (i = 0; i < boolcnt; i++) { 79 char *name = boollist[i]->name; 80 int active = boollist[i]->active; 81 rc = sepol_bool_key_create(avc->handle, name, &key); 82 if (rc < 0) { 83 PyErr_SetString( PyExc_RuntimeError, 84 "Could not create boolean key.\n"); 85 break; 86 } 87 rc = sepol_bool_query(avc->handle, 88 avc->policydb, 89 key, &boolean); 90 91 if (rc < 0) { 92 snprintf(errormsg, sizeof(errormsg), 93 "Could not find boolean %s.\n", name); 94 PyErr_SetString( PyExc_RuntimeError, errormsg); 95 break; 96 } 97 98 sepol_bool_set_value(boolean, !active); 99 100 rc = sepol_bool_set(avc->handle, 101 avc->policydb, 102 key, boolean); 103 if (rc < 0) { 104 snprintf(errormsg, sizeof(errormsg), 105 "Could not set boolean data %s.\n", name); 106 PyErr_SetString( PyExc_RuntimeError, errormsg); 107 break; 108 } 109 110 /* Reproduce the computation. */ 111 rc = sepol_compute_av_reason(avc->ssid, avc->tsid, avc->tclass, 112 avc->av, &avd, &reason); 113 if (rc < 0) { 114 snprintf(errormsg, sizeof(errormsg), 115 "Error during access vector computation, skipping..."); 116 PyErr_SetString( PyExc_RuntimeError, errormsg); 117 118 sepol_bool_free(boolean); 119 break; 120 } else { 121 if (!reason) { 122 foundlist[fcnt] = i; 123 fcnt++; 124 } 125 sepol_bool_set_value(boolean, active); 126 rc = sepol_bool_set(avc->handle, 127 avc->policydb, key, 128 boolean); 129 if (rc < 0) { 130 snprintf(errormsg, sizeof(errormsg), 131 "Could not set boolean data %s.\n", 132 name); 133 134 PyErr_SetString( PyExc_RuntimeError, errormsg); 135 break; 136 } 137 } 138 sepol_bool_free(boolean); 139 sepol_bool_key_free(key); 140 key = NULL; 141 boolean = NULL; 142 } 143 if (key) 144 sepol_bool_key_free(key); 145 146 if (boolean) 147 sepol_bool_free(boolean); 148 149 if (fcnt > 0) { 150 *bools = calloc(sizeof(struct boolean_t), fcnt + 1); 151 struct boolean_t *b = *bools; 152 for (i = 0; i < fcnt; i++) { 153 int ctr = foundlist[i]; 154 b[i].name = strdup(boollist[ctr]->name); 155 b[i].active = !boollist[ctr]->active; 156 } 157 } 158 free(foundlist); 159 return fcnt; 160} 161 162static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) { 163 PyObject *result = 0; 164 165 if (PyArg_ParseTuple(args,(char *)":finish")) { 166 int i = 0; 167 if (! avc) 168 Py_RETURN_NONE; 169 170 for (i = 0; i < boolcnt; i++) { 171 free(boollist[i]->name); 172 free(boollist[i]); 173 } 174 free(boollist); 175 sepol_sidtab_shutdown(&sidtab); 176 sepol_sidtab_destroy(&sidtab); 177 sepol_policydb_free(avc->policydb); 178 sepol_handle_destroy(avc->handle); 179 free(avc); 180 avc = NULL; 181 boollist = NULL; 182 boolcnt = 0; 183 184 /* Boilerplate to return "None" */ 185 Py_RETURN_NONE; 186 } 187 return result; 188} 189 190 191static int __policy_init(const char *init_path) 192{ 193 FILE *fp; 194 char path[PATH_MAX]; 195 char errormsg[PATH_MAX]; 196 struct sepol_policy_file *pf = NULL; 197 int rc; 198 unsigned int cnt; 199 200 path[PATH_MAX-1] = '\0'; 201 if (init_path) { 202 strncpy(path, init_path, PATH_MAX-1); 203 fp = fopen(path, "r"); 204 if (!fp) { 205 snprintf(errormsg, sizeof(errormsg), 206 "unable to open %s: %s\n", 207 path, strerror(errno)); 208 PyErr_SetString( PyExc_ValueError, errormsg); 209 return 1; 210 } 211 } else { 212 fp = fopen(selinux_current_policy_path(), "r"); 213 if (!fp) { 214 snprintf(errormsg, sizeof(errormsg), 215 "unable to open %s: %s\n", 216 selinux_current_policy_path(), 217 strerror(errno)); 218 PyErr_SetString( PyExc_ValueError, errormsg); 219 return 1; 220 } 221 } 222 223 avc = calloc(sizeof(struct avc_t), 1); 224 if (!avc) { 225 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 226 fclose(fp); 227 return 1; 228 } 229 230 /* Set up a policydb directly so that we can mutate it later 231 for testing what booleans might have allowed the access. 232 Otherwise, we'd just use sepol_set_policydb_from_file() here. */ 233 if (sepol_policy_file_create(&pf) || 234 sepol_policydb_create(&avc->policydb)) { 235 snprintf(errormsg, sizeof(errormsg), 236 "policydb_init failed: %s\n", strerror(errno)); 237 PyErr_SetString( PyExc_RuntimeError, errormsg); 238 fclose(fp); 239 return 1; 240 } 241 sepol_policy_file_set_fp(pf, fp); 242 if (sepol_policydb_read(avc->policydb, pf)) { 243 snprintf(errormsg, sizeof(errormsg), 244 "invalid binary policy %s\n", path); 245 PyErr_SetString( PyExc_ValueError, errormsg); 246 fclose(fp); 247 return 1; 248 } 249 fclose(fp); 250 sepol_set_policydb(&avc->policydb->p); 251 avc->handle = sepol_handle_create(); 252 /* Turn off messages */ 253 sepol_msg_set_callback(avc->handle, NULL, NULL); 254 255 rc = sepol_bool_count(avc->handle, 256 avc->policydb, &cnt); 257 if (rc < 0) { 258 PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n"); 259 return 1; 260 } 261 262 boollist = calloc(cnt, sizeof(*boollist)); 263 if (!boollist) { 264 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 265 return 1; 266 } 267 268 sepol_bool_iterate(avc->handle, avc->policydb, 269 load_booleans, (void *)NULL); 270 271 /* Initialize the sidtab for subsequent use by sepol_context_to_sid 272 and sepol_compute_av_reason. */ 273 rc = sepol_sidtab_init(&sidtab); 274 if (rc < 0) { 275 PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n"); 276 free(boollist); 277 return 1; 278 } 279 sepol_set_sidtab(&sidtab); 280 return 0; 281} 282 283static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { 284 int result; 285 char *init_path=NULL; 286 if (avc) { 287 PyErr_SetString( PyExc_RuntimeError, "init called multiple times"); 288 return NULL; 289 } 290 if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path)) 291 return NULL; 292 result = __policy_init(init_path); 293 return Py_BuildValue("i", result); 294} 295 296#define RETURN(X) \ 297 { \ 298 return Py_BuildValue("iO", (X), Py_None); \ 299 } 300 301static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) { 302 security_context_t scon; 303 security_context_t tcon; 304 char *tclassstr; 305 PyObject *listObj; 306 PyObject *strObj; 307 int numlines; 308 struct boolean_t *bools; 309 unsigned int reason; 310 sepol_security_id_t ssid, tsid; 311 sepol_security_class_t tclass; 312 sepol_access_vector_t perm, av; 313 struct sepol_av_decision avd; 314 int rc; 315 int i=0; 316 317 if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj)) 318 return NULL; 319 320 /* get the number of lines passed to us */ 321 numlines = PyList_Size(listObj); 322 323 /* should raise an error here. */ 324 if (numlines < 0) return NULL; /* Not a list */ 325 326 if (!avc) 327 RETURN(NOPOLICY) 328 329 rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid); 330 if (rc < 0) 331 RETURN(BADSCON) 332 333 rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid); 334 if (rc < 0) 335 RETURN(BADTCON) 336 337 tclass = string_to_security_class(tclassstr); 338 if (!tclass) 339 RETURN(BADTCLASS) 340 341 /* Convert the permission list to an AV. */ 342 av = 0; 343 344 /* iterate over items of the list, grabbing strings, and parsing 345 for numbers */ 346 for (i=0; i<numlines; i++){ 347 char *permstr; 348 349 /* grab the string object from the next element of the list */ 350 strObj = PyList_GetItem(listObj, i); /* Can't fail */ 351 352 /* make it a string */ 353#if PY_MAJOR_VERSION >= 3 354 permstr = _PyUnicode_AsString( strObj ); 355#else 356 permstr = PyString_AsString( strObj ); 357#endif 358 359 perm = string_to_av_perm(tclass, permstr); 360 if (!perm) 361 RETURN(BADPERM) 362 363 av |= perm; 364 } 365 366 /* Reproduce the computation. */ 367 rc = sepol_compute_av_reason(ssid, tsid, tclass, av, &avd, &reason); 368 if (rc < 0) 369 RETURN(BADCOMPUTE) 370 371 if (!reason) 372 RETURN(ALLOW) 373 374 if (reason & SEPOL_COMPUTEAV_TE) { 375 avc->ssid = ssid; 376 avc->tsid = tsid; 377 avc->tclass = tclass; 378 avc->av = av; 379 if (check_booleans(&bools) == 0) { 380 if (av & ~avd.auditdeny) { 381 RETURN(DONTAUDIT) 382 } else { 383 RETURN(TERULE) 384 } 385 } else { 386 PyObject *outboollist; 387 struct boolean_t *b = bools; 388 int len=0; 389 while (b->name) { 390 len++; b++; 391 } 392 b = bools; 393 outboollist = PyList_New(len); 394 len=0; 395 while(b->name) { 396 PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active); 397 PyList_SetItem(outboollist, len++, bool_); 398 b++; 399 } 400 free(bools); 401 /* 'N' steals the reference to outboollist */ 402 return Py_BuildValue("iN", BOOLEAN, outboollist); 403 } 404 } 405 406 if (reason & SEPOL_COMPUTEAV_CONS) { 407 RETURN(CONSTRAINT) 408 } 409 410 if (reason & SEPOL_COMPUTEAV_RBAC) 411 RETURN(RBAC) 412 413 RETURN(BADCOMPUTE) 414} 415 416static PyMethodDef audit2whyMethods[] = { 417 {"init", init, METH_VARARGS, 418 "Initialize policy database."}, 419 {"analyze", analyze, METH_VARARGS, 420 "Analyze AVC."}, 421 {"finish", finish, METH_VARARGS, 422 "Finish using policy, free memory."}, 423 {NULL, NULL, 0, NULL} /* Sentinel */ 424}; 425 426#if PY_MAJOR_VERSION >= 3 427/* Module-initialization logic specific to Python 3 */ 428struct module_state { 429 /* empty for now */ 430}; 431static struct PyModuleDef moduledef = { 432 PyModuleDef_HEAD_INIT, 433 "audit2why", 434 NULL, 435 sizeof(struct module_state), 436 audit2whyMethods, 437 NULL, 438 NULL, 439 NULL, 440 NULL 441}; 442 443PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */ 444PyMODINIT_FUNC PyInit_audit2why(void) 445#else 446PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */ 447PyMODINIT_FUNC initaudit2why(void) 448#endif 449{ 450 PyObject *m; 451#if PY_MAJOR_VERSION >= 3 452 m = PyModule_Create(&moduledef); 453 if (m == NULL) { 454 return NULL; 455 } 456#else 457 m = Py_InitModule("audit2why", audit2whyMethods); 458#endif 459 PyModule_AddIntConstant(m,"UNKNOWN", UNKNOWN); 460 PyModule_AddIntConstant(m,"BADSCON", BADSCON); 461 PyModule_AddIntConstant(m,"BADTCON", BADTCON); 462 PyModule_AddIntConstant(m,"BADTCLASS", BADTCLASS); 463 PyModule_AddIntConstant(m,"BADPERM", BADPERM); 464 PyModule_AddIntConstant(m,"BADCOMPUTE", BADCOMPUTE); 465 PyModule_AddIntConstant(m,"NOPOLICY", NOPOLICY); 466 PyModule_AddIntConstant(m,"ALLOW", ALLOW); 467 PyModule_AddIntConstant(m,"DONTAUDIT", DONTAUDIT); 468 PyModule_AddIntConstant(m,"TERULE", TERULE); 469 PyModule_AddIntConstant(m,"BOOLEAN", BOOLEAN); 470 PyModule_AddIntConstant(m,"CONSTRAINT", CONSTRAINT); 471 PyModule_AddIntConstant(m,"RBAC", RBAC); 472 473#if PY_MAJOR_VERSION >= 3 474 return m; 475#endif 476} 477