1/* $OpenBSD: shm_open.c,v 1.9 2017/09/10 18:20:00 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 37static void 38makeshmpath(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 46int 47shm_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 = HIDDEN(open)(shmpath, flags, mode); 65 if (fd == -1) 66 return -1; 67 if (fstat(fd, &sb) == -1 || !S_ISREG(sb.st_mode)) { 68 HIDDEN(close)(fd); 69 errno = EINVAL; 70 return -1; 71 } 72 if (sb.st_uid != geteuid()) { 73 HIDDEN(close)(fd); 74 errno = EPERM; 75 return -1; 76 } 77 return fd; 78} 79DEF_WEAK(shm_open); 80 81int 82shm_unlink(const char *path) 83{ 84 char shmpath[SHM_PATH_SIZE]; 85 86 makeshmpath(path, shmpath, sizeof(shmpath)); 87 return unlink(shmpath); 88} 89 90int 91shm_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