int parse_self_maps_lite(struct vm_area_list *vms) { FILE *maps; vm_area_list_init(vms); maps = fopen_proc(PROC_SELF, "maps"); if (maps == NULL) { pr_perror("Can't open self maps"); return -1; } while (fgets(buf, BUF_SIZE, maps) != NULL) { struct vma_area *vma; char *end; vma = alloc_vma_area(); if (!vma) { fclose(maps); return -1; } vma->e->start = strtoul(buf, &end, 16); vma->e->end = strtoul(end + 1, NULL, 16); list_add_tail(&vma->list, &vms->h); vms->nr++; pr_debug("Parsed %"PRIx64"-%"PRIx64" vma\n", vma->e->start, vma->e->end); } fclose(maps); return 0; }
static int apparmor_get_label(pid_t pid, char **profile_name) { FILE *f; char *space; f = fopen_proc(pid, "attr/current"); if (!f) return -1; if (fscanf(f, "%ms", profile_name) != 1) { fclose(f); pr_perror("err scanfing"); return -1; } fclose(f); /* * A profile name can be followed by an enforcement mode, e.g. * lxc-default-with-nesting (enforced) * but the profile name is just the part before the space. */ space = strstr(*profile_name, " "); if (space) *space = 0; /* * An "unconfined" value means there is no profile, so we don't need to * worry about trying to restore one. */ if (strcmp(*profile_name, "unconfined") == 0) *profile_name = NULL; return 0; }
int parse_cpuinfo_features(int (*handler)(char *tok)) { FILE *cpuinfo; cpuinfo = fopen_proc(PROC_GEN, "cpuinfo"); if (!cpuinfo) { pr_perror("Can't open cpuinfo file"); return -1; } while (fgets(buf, BUF_SIZE, cpuinfo)) { char *tok; if (strncmp(buf, "flags\t\t:", 8)) continue; for (tok = strtok(buf, " \t\n"); tok; tok = strtok(NULL, " \t\n")) { if (handler(tok) < 0) break; } } fclose(cpuinfo); return 0; }
static int parse_self_maps(unsigned long vm_start, dev_t *device) { FILE *maps; char buf[1024]; maps = fopen_proc(PROC_SELF, "maps"); if (maps == NULL) return -1; while (fgets(buf, sizeof(buf), maps) != NULL) { char *end, *aux; unsigned long start; int maj, min; start = strtoul(buf, &end, 16); if (vm_start > start) continue; if (vm_start < start) break; /* It's ours */ aux = strchr(end + 1, ' '); /* end prot */ aux = strchr(aux + 1, ' '); /* prot pgoff */ aux = strchr(aux + 1, ' '); /* pgoff dev */ maj = strtoul(aux + 1, &end, 16); min = strtoul(end + 1, NULL, 16); *device = makedev(maj, min); fclose(maps); return 0; } fclose(maps); return -1; }
int parse_pid_status(pid_t pid, struct proc_status_creds *cr) { int done = 0; FILE *f; char str[64]; f = fopen_proc(pid, "status"); if (f == NULL) { pr_perror("Can't open proc status"); return -1; } while (done < 6 && fgets(str, sizeof(str), f)) { if (!strncmp(str, "Uid:", 4)) { if (ids_parse(str + 5, cr->uids)) goto err_parse; done++; } if (!strncmp(str, "Gid:", 4)) { if (ids_parse(str + 5, cr->gids)) goto err_parse; done++; } if (!strncmp(str, "CapInh:", 7)) { if (cap_parse(str + 8, cr->cap_inh)) goto err_parse; done++; } if (!strncmp(str, "CapEff:", 7)) { if (cap_parse(str + 8, cr->cap_eff)) goto err_parse; done++; } if (!strncmp(str, "CapPrm:", 7)) { if (cap_parse(str + 8, cr->cap_prm)) goto err_parse; done++; } if (!strncmp(str, "CapBnd:", 7)) { if (cap_parse(str + 8, cr->cap_bnd)) goto err_parse; done++; } } if (done != 6) { err_parse: pr_err("Error parsing proc status file\n"); fclose(f); return -1; } fclose(f); return 0; }
int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_files) { struct vma_area *vma_area = NULL; unsigned long start, end, pgoff; unsigned long ino; char r, w, x, s; int dev_maj, dev_min; int ret = -1; DIR *map_files_dir = NULL; FILE *smaps = NULL; vma_area_list->nr = 0; vma_area_list->longest = 0; vma_area_list->priv_size = 0; INIT_LIST_HEAD(&vma_area_list->h); smaps = fopen_proc(pid, "smaps"); if (!smaps) goto err; if (use_map_files) { map_files_dir = opendir_proc(pid, "map_files"); if (!map_files_dir) /* old kernel? */ goto err; } while (fgets(buf, BUF_SIZE, smaps)) { int num; char file_path[6]; if (!is_vma_range_fmt(buf)) { if (!strncmp(buf, "Nonlinear", 9)) { BUG_ON(!vma_area); pr_err("Nonlinear mapping found %016"PRIx64"-%016"PRIx64"\n", vma_area->vma.start, vma_area->vma.end); /* * VMA is already on list and will be * freed later as list get destroyed. */ vma_area = NULL; goto err; } else if (!strncmp(buf, "VmFlags: ", 9)) { BUG_ON(!vma_area); if (parse_vmflags(&buf[9], vma_area)) goto err; continue; } else continue; } vma_area = alloc_vma_area(); if (!vma_area) goto err; memset(file_path, 0, 6); num = sscanf(buf, "%lx-%lx %c%c%c%c %lx %02x:%02x %lu %5s", &start, &end, &r, &w, &x, &s, &pgoff, &dev_maj, &dev_min, &ino, file_path); if (num < 10) { pr_err("Can't parse: %s\n", buf); goto err; } if (map_files_dir) { char path[32]; /* Figure out if it's file mapping */ snprintf(path, sizeof(path), "%lx-%lx", start, end); /* * Note that we "open" it in dumper process space * so later we might refer to it via /proc/self/fd/vm_file_fd * if needed. */ vma_area->vm_file_fd = openat(dirfd(map_files_dir), path, O_RDONLY); if (vma_area->vm_file_fd < 0) { if (errno == ENXIO) { struct stat buf; if (fstatat(dirfd(map_files_dir), path, &buf, 0)) goto err_bogus_mapfile; if (!S_ISSOCK(buf.st_mode)) goto err_bogus_mapfile; pr_info("Found socket %"PRIu64" mapping @%lx\n", buf.st_ino, start); vma_area->vma.status |= VMA_AREA_SOCKET | VMA_AREA_REGULAR; vma_area->vm_socket_id = buf.st_ino; } else if (errno != ENOENT) goto err_bogus_mapfile; } } vma_area->vma.start = start; vma_area->vma.end = end; vma_area->vma.pgoff = pgoff; vma_area->vma.prot = PROT_NONE; if (r == 'r') vma_area->vma.prot |= PROT_READ; if (w == 'w') vma_area->vma.prot |= PROT_WRITE; if (x == 'x') vma_area->vma.prot |= PROT_EXEC; if (s == 's') vma_area->vma.flags = MAP_SHARED; else if (s == 'p') vma_area->vma.flags = MAP_PRIVATE; else { pr_err("Unexpected VMA met (%c)\n", s); goto err; } if (vma_area->vma.status != 0) { goto done; } else if (strstr(buf, "[vsyscall]")) { vma_area->vma.status |= VMA_AREA_VSYSCALL; } else if (strstr(buf, "[vdso]")) { vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO; } else if (strstr(buf, "[heap]")) { vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_HEAP; } else { vma_area->vma.status = VMA_AREA_REGULAR; } /* * Some mapping hints for restore, we save this on * disk and restore might need to analyze it. */ if (vma_area->vm_file_fd >= 0) { struct stat st_buf; if (fstat(vma_area->vm_file_fd, &st_buf) < 0) { pr_perror("Failed fstat on %d's map %lu", pid, start); goto err; } if (!S_ISREG(st_buf.st_mode) && !(S_ISCHR(st_buf.st_mode) && st_buf.st_rdev == DEVZERO)) { pr_err("Can't handle non-regular mapping on %d's map %lu\n", pid, start); goto err; } /* * /dev/zero stands for anon-shared mapping * otherwise it's some file mapping. */ if (is_anon_shmem_map(st_buf.st_dev)) { if (!(vma_area->vma.flags & MAP_SHARED)) goto err_bogus_mapping; vma_area->vma.flags |= MAP_ANONYMOUS; vma_area->vma.status |= VMA_ANON_SHARED; vma_area->vma.shmid = st_buf.st_ino; if (!strcmp(file_path, "/SYSV")) { pr_info("path: %s\n", file_path); vma_area->vma.status |= VMA_AREA_SYSVIPC; } } else { if (vma_area->vma.flags & MAP_PRIVATE) vma_area->vma.status |= VMA_FILE_PRIVATE; else vma_area->vma.status |= VMA_FILE_SHARED; } } else { /* * No file but mapping -- anonymous one. */ if (vma_area->vma.flags & MAP_SHARED) { vma_area->vma.status |= VMA_ANON_SHARED; vma_area->vma.shmid = ino; } else { vma_area->vma.status |= VMA_ANON_PRIVATE; } vma_area->vma.flags |= MAP_ANONYMOUS; } done: list_add_tail(&vma_area->list, &vma_area_list->h); vma_area_list->nr++; if (privately_dump_vma(vma_area)) { unsigned long pages; pages = vma_area_len(vma_area) / PAGE_SIZE; vma_area_list->priv_size += pages; vma_area_list->longest = max(vma_area_list->longest, pages); } } vma_area = NULL; ret = 0; err: if (smaps) fclose(smaps); if (map_files_dir) closedir(map_files_dir); xfree(vma_area); return ret; err_bogus_mapping: pr_err("Bogus mapping 0x%"PRIx64"-0x%"PRIx64" (flags: %#x vm_file_fd: %d)\n", vma_area->vma.start, vma_area->vma.end, vma_area->vma.flags, vma_area->vm_file_fd); goto err; err_bogus_mapfile: pr_perror("Can't open %d's mapfile link %lx", pid, start); goto err; }