1 /* $OpenBSD: shm_open.c,v 1.6 2015/08/31 02:53:57 guenther 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 != getuid()) { 73 close(fd); 74 errno = EPERM; 75 return -1; 76 } 77 return fd; 78 } 79 80 int 81 shm_unlink(const char *path) 82 { 83 char shmpath[SHM_PATH_SIZE]; 84 85 makeshmpath(path, shmpath, sizeof(shmpath)); 86 return unlink(shmpath); 87 } 88 89 int 90 shm_mkstemp(char *template) 91 { 92 size_t templatelen; 93 char *t; 94 int i, fd; 95 96 templatelen = strlen(template); 97 t = malloc(templatelen + 1); 98 if (!t) 99 return -1; 100 t[templatelen] = '\0'; 101 102 fd = -1; 103 for (i = 0; i < INT_MAX; i++) { 104 memcpy(t, template, templatelen); 105 if (!_mktemp(t)) 106 break; 107 fd = shm_open(t, O_RDWR | O_EXCL | O_CREAT, 0600); 108 if (fd != -1) { 109 memcpy(template, t, templatelen); 110 break; 111 } 112 } 113 114 free(t); 115 return fd; 116 } 117 118