1 /* $OpenBSD: shm_open.c,v 1.8 2015/12/10 13:03:22 tedu Exp $ */ 2 /* 3 * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/types.h> 18 #include <sys/mman.h> 19 #include <sys/stat.h> 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <limits.h> 24 #include <sha2.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 /* SHA256_DIGEST_STRING_LENGTH includes nul */ 31 /* "/tmp/" + sha256 + ".shm" */ 32 #define SHM_PATH_SIZE (5 + SHA256_DIGEST_STRING_LENGTH + 4) 33 34 /* O_CLOEXEC and O_NOFOLLOW are extensions to POSIX */ 35 #define OK_FLAGS (O_CREAT | O_EXCL | O_TRUNC | O_CLOEXEC | O_NOFOLLOW) 36 37 static void 38 makeshmpath(const char *origpath, char *shmpath, size_t len) 39 { 40 char buf[SHA256_DIGEST_STRING_LENGTH]; 41 42 SHA256Data(origpath, strlen(origpath), buf); 43 snprintf(shmpath, len, "/tmp/%s.shm", buf); 44 } 45 46 int 47 shm_open(const char *path, int flags, mode_t mode) 48 { 49 char shmpath[SHM_PATH_SIZE]; 50 struct stat sb; 51 int fd; 52 53 if (((flags & O_ACCMODE) != O_RDONLY && (flags & O_ACCMODE) != O_RDWR) 54 || (flags & ~(O_ACCMODE | OK_FLAGS))) { 55 errno = EINVAL; 56 return -1; 57 } 58 59 flags |= O_CLOEXEC | O_NOFOLLOW; 60 mode = mode & 0600; 61 62 makeshmpath(path, shmpath, sizeof(shmpath)); 63 64 fd = open(shmpath, flags, mode); 65 if (fd == -1) 66 return -1; 67 if (fstat(fd, &sb) == -1 || !S_ISREG(sb.st_mode)) { 68 close(fd); 69 errno = EINVAL; 70 return -1; 71 } 72 if (sb.st_uid != geteuid()) { 73 close(fd); 74 errno = EPERM; 75 return -1; 76 } 77 return fd; 78 } 79 DEF_WEAK(shm_open); 80 81 int 82 shm_unlink(const char *path) 83 { 84 char shmpath[SHM_PATH_SIZE]; 85 86 makeshmpath(path, shmpath, sizeof(shmpath)); 87 return unlink(shmpath); 88 } 89 90 int 91 shm_mkstemp(char *template) 92 { 93 size_t templatelen; 94 char *t; 95 int i, fd; 96 97 templatelen = strlen(template); 98 t = malloc(templatelen + 1); 99 if (!t) 100 return -1; 101 t[templatelen] = '\0'; 102 103 fd = -1; 104 for (i = 0; i < INT_MAX; i++) { 105 memcpy(t, template, templatelen); 106 if (!_mktemp(t)) 107 break; 108 fd = shm_open(t, O_RDWR | O_EXCL | O_CREAT, 0600); 109 if (fd != -1) { 110 memcpy(template, t, templatelen); 111 break; 112 } 113 } 114 115 free(t); 116 return fd; 117 } 118 119