audit2why.c revision 019e6fd6d4e383ae82b65a2f5868e377dd8af571
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 int vers = 0; 195 char path[PATH_MAX]; 196 char errormsg[PATH_MAX]; 197 struct sepol_policy_file *pf = NULL; 198 int rc; 199 unsigned int cnt; 200 201 path[PATH_MAX-1] = '\0'; 202 if (init_path) { 203 strncpy(path, init_path, PATH_MAX-1); 204 fp = fopen(path, "r"); 205 if (!fp) { 206 snprintf(errormsg, sizeof(errormsg), 207 "unable to open %s: %s\n", 208 path, strerror(errno)); 209 PyErr_SetString( PyExc_ValueError, errormsg); 210 return 1; 211 } 212 } else { 213 vers = sepol_policy_kern_vers_max(); 214 if (vers < 0) { 215 snprintf(errormsg, sizeof(errormsg), 216 "Could not get policy version: %s\n", 217 strerror(errno)); 218 PyErr_SetString( PyExc_ValueError, errormsg); 219 return 1; 220 } 221 snprintf(path, PATH_MAX, "%s.%d", 222 selinux_binary_policy_path(), vers); 223 fp = fopen(path, "r"); 224 while (!fp && errno == ENOENT && --vers) { 225 snprintf(path, PATH_MAX, "%s.%d", 226 selinux_binary_policy_path(), vers); 227 fp = fopen(path, "r"); 228 } 229 if (!fp) { 230 snprintf(errormsg, sizeof(errormsg), 231 "unable to open %s.%d: %s\n", 232 selinux_binary_policy_path(), 233 security_policyvers(), strerror(errno)); 234 PyErr_SetString( PyExc_ValueError, errormsg); 235 return 1; 236 } 237 } 238 239 avc = calloc(sizeof(struct avc_t), 1); 240 if (!avc) { 241 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 242 fclose(fp); 243 return 1; 244 } 245 246 /* Set up a policydb directly so that we can mutate it later 247 for testing what booleans might have allowed the access. 248 Otherwise, we'd just use sepol_set_policydb_from_file() here. */ 249 if (sepol_policy_file_create(&pf) || 250 sepol_policydb_create(&avc->policydb)) { 251 snprintf(errormsg, sizeof(errormsg), 252 "policydb_init failed: %s\n", strerror(errno)); 253 PyErr_SetString( PyExc_RuntimeError, errormsg); 254 fclose(fp); 255 return 1; 256 } 257 sepol_policy_file_set_fp(pf, fp); 258 if (sepol_policydb_read(avc->policydb, pf)) { 259 snprintf(errormsg, sizeof(errormsg), 260 "invalid binary policy %s\n", path); 261 PyErr_SetString( PyExc_ValueError, errormsg); 262 fclose(fp); 263 return 1; 264 } 265 fclose(fp); 266 sepol_set_policydb(&avc->policydb->p); 267 avc->handle = sepol_handle_create(); 268 /* Turn off messages */ 269 sepol_msg_set_callback(avc->handle, NULL, NULL); 270 271 rc = sepol_bool_count(avc->handle, 272 avc->policydb, &cnt); 273 if (rc < 0) { 274 PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n"); 275 return 1; 276 } 277 278 boollist = calloc(cnt, sizeof(struct boolean_t)); 279 if (!boollist) { 280 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 281 return 1; 282 } 283 284 sepol_bool_iterate(avc->handle, avc->policydb, 285 load_booleans, (void *)NULL); 286 287 /* Initialize the sidtab for subsequent use by sepol_context_to_sid 288 and sepol_compute_av_reason. */ 289 rc = sepol_sidtab_init(&sidtab); 290 if (rc < 0) { 291 PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n"); 292 free(boollist); 293 return 1; 294 } 295 sepol_set_sidtab(&sidtab); 296 return 0; 297} 298 299static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { 300 int result; 301 char *init_path=NULL; 302 if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path)) 303 return NULL; 304 result = __policy_init(init_path); 305 return Py_BuildValue("i", result); 306} 307 308#define RETURN(X) \ 309 PyTuple_SetItem(result, 0, Py_BuildValue("i", X)); \ 310 return result; 311 312static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) { 313 security_context_t scon; 314 security_context_t tcon; 315 char *tclassstr; 316 PyObject *listObj; 317 PyObject *strObj; 318 int numlines; 319 struct boolean_t *bools; 320 unsigned int reason; 321 sepol_security_id_t ssid, tsid; 322 sepol_security_class_t tclass; 323 sepol_access_vector_t perm, av; 324 struct sepol_av_decision avd; 325 int rc; 326 int i=0; 327 PyObject *result = PyTuple_New(2); 328 if (!result) return NULL; 329 Py_INCREF(Py_None); 330 PyTuple_SetItem(result, 1, Py_None); 331 332 if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj)) 333 return NULL; 334 335 /* get the number of lines passed to us */ 336 numlines = PyList_Size(listObj); 337 338 /* should raise an error here. */ 339 if (numlines < 0) return NULL; /* Not a list */ 340 341 if (!avc) { 342 RETURN(NOPOLICY) 343 } 344 345 rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid); 346 if (rc < 0) { 347 RETURN(BADSCON) 348 } 349 rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid); 350 if (rc < 0) { 351 RETURN(BADTCON) 352 } 353 tclass = string_to_security_class(tclassstr); 354 if (!tclass) { 355 RETURN(BADTCLASS) 356 } 357 /* Convert the permission list to an AV. */ 358 av = 0; 359 360 /* iterate over items of the list, grabbing strings, and parsing 361 for numbers */ 362 for (i=0; i<numlines; i++){ 363 char *permstr; 364 365 /* grab the string object from the next element of the list */ 366 strObj = PyList_GetItem(listObj, i); /* Can't fail */ 367 368 /* make it a string */ 369#if PY_MAJOR_VERSION >= 3 370 permstr = _PyUnicode_AsString( strObj ); 371#else 372 permstr = PyString_AsString( strObj ); 373#endif 374 375 perm = string_to_av_perm(tclass, permstr); 376 if (!perm) { 377 RETURN(BADPERM) 378 } 379 av |= perm; 380 } 381 382 /* Reproduce the computation. */ 383 rc = sepol_compute_av_reason(ssid, tsid, tclass, av, &avd, &reason); 384 if (rc < 0) { 385 RETURN(BADCOMPUTE) 386 } 387 388 if (!reason) { 389 RETURN(ALLOW) 390 } 391 if (reason & SEPOL_COMPUTEAV_TE) { 392 avc->ssid = ssid; 393 avc->tsid = tsid; 394 avc->tclass = tclass; 395 avc->av = av; 396 if (check_booleans(&bools) == 0) { 397 if (av & ~avd.auditdeny) { 398 RETURN(DONTAUDIT) 399 } else { 400 RETURN(TERULE) 401 } 402 } else { 403 PyTuple_SetItem(result, 0, Py_BuildValue("i", BOOLEAN)); 404 struct boolean_t *b = bools; 405 int len=0; 406 while (b->name) { 407 len++; b++; 408 } 409 b = bools; 410 PyObject *outboollist = PyTuple_New(len); 411 len=0; 412 while(b->name) { 413 PyObject *bool = Py_BuildValue("(si)", b->name, b->active); 414 PyTuple_SetItem(outboollist, len++, bool); 415 b++; 416 } 417 free(bools); 418 PyTuple_SetItem(result, 1, outboollist); 419 return result; 420 } 421 } 422 423 if (reason & SEPOL_COMPUTEAV_CONS) { 424 RETURN(CONSTRAINT); 425 } 426 427 if (reason & SEPOL_COMPUTEAV_RBAC) { 428 RETURN(RBAC) 429 } 430 RETURN(BADCOMPUTE) 431} 432 433static PyMethodDef audit2whyMethods[] = { 434 {"init", init, METH_VARARGS, 435 "Initialize policy database."}, 436 {"analyze", analyze, METH_VARARGS, 437 "Analyze AVC."}, 438 {"finish", finish, METH_VARARGS, 439 "Finish using policy, free memory."}, 440 {NULL, NULL, 0, NULL} /* Sentinel */ 441}; 442 443#if PY_MAJOR_VERSION >= 3 444/* Module-initialization logic specific to Python 3 */ 445struct module_state { 446 /* empty for now */ 447}; 448static struct PyModuleDef moduledef = { 449 PyModuleDef_HEAD_INIT, 450 "audit2why", 451 NULL, 452 sizeof(struct module_state), 453 audit2whyMethods, 454 NULL, 455 NULL, 456 NULL, 457 NULL 458}; 459 460PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */ 461PyMODINIT_FUNC PyInit_audit2why(void) 462#else 463PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */ 464PyMODINIT_FUNC initaudit2why(void) 465#endif 466{ 467 PyObject *m; 468#if PY_MAJOR_VERSION >= 3 469 m = PyModule_Create(&moduledef); 470 if (m == NULL) { 471 return NULL; 472 } 473#else 474 m = Py_InitModule("audit2why", audit2whyMethods); 475#endif 476 PyModule_AddIntConstant(m,"UNKNOWN", UNKNOWN); 477 PyModule_AddIntConstant(m,"BADSCON", BADSCON); 478 PyModule_AddIntConstant(m,"BADTCON", BADTCON); 479 PyModule_AddIntConstant(m,"BADTCLASS", BADTCLASS); 480 PyModule_AddIntConstant(m,"BADPERM", BADPERM); 481 PyModule_AddIntConstant(m,"BADCOMPUTE", BADCOMPUTE); 482 PyModule_AddIntConstant(m,"NOPOLICY", NOPOLICY); 483 PyModule_AddIntConstant(m,"ALLOW", ALLOW); 484 PyModule_AddIntConstant(m,"DONTAUDIT", DONTAUDIT); 485 PyModule_AddIntConstant(m,"TERULE", TERULE); 486 PyModule_AddIntConstant(m,"BOOLEAN", BOOLEAN); 487 PyModule_AddIntConstant(m,"CONSTRAINT", CONSTRAINT); 488 PyModule_AddIntConstant(m,"RBAC", RBAC); 489 490#if PY_MAJOR_VERSION >= 3 491 return m; 492#endif 493} 494