diff options
-rw-r--r-- | ChangeLog.txt | 15 | ||||
-rwxr-xr-x | makewrappers | 1 | ||||
-rw-r--r-- | ports/darwin/guts/open.c | 3 | ||||
-rw-r--r-- | ports/linux/guts/__xmknodat.c | 3 | ||||
-rw-r--r-- | ports/linux/guts/openat.c | 3 | ||||
-rw-r--r-- | ports/unix/guts/fchmodat.c | 26 | ||||
-rw-r--r-- | ports/unix/guts/mkdirat.c | 3 | ||||
-rw-r--r-- | ports/unix/guts/mknodat.c | 3 | ||||
-rw-r--r-- | ports/unix/guts/umask.c | 14 | ||||
-rw-r--r-- | ports/unix/wrapfuncs.in | 1 | ||||
-rw-r--r-- | pseudo_client.c | 5 | ||||
-rw-r--r-- | pseudo_client.h | 6 |
12 files changed, 78 insertions, 5 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index 113f675..cc966ce 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,18 @@ +2014-05-27: + * (seebs) start noticing umask, mask it out from open or mkdir + calls rather than relying on underlying open/mkdir to do it. + +2014-05-16: + * (seebs) fchmodat: don't drop flags, report failures, to improve + compatibility/consistency. Cache the knowledge that + AT_SYMLINK_NOFOLLOW gets ENOTSUP. + * (seebs) mask out group/other write bits in real filesystem to + reduce risks when assembling a rootfs including world-writeable + directories. + +2014-05-15: + * (seebs) drop flags when calling fchmodat() to appease GNU tar. + 2013-02-27: * (seebs) Oh, hey, what if I took out my debug messages? * (seebs) update docs a bit to reduce bitrot diff --git a/makewrappers b/makewrappers index e87cc56..0127766 100755 --- a/makewrappers +++ b/makewrappers @@ -204,6 +204,7 @@ class Function: 'uid_t': '0', 'int': '-1', 'long': '-1', + 'mode_t': '0', 'ssize_t': '-1' } diff --git a/ports/darwin/guts/open.c b/ports/darwin/guts/open.c index c66cc15..520bb70 100644 --- a/ports/darwin/guts/open.c +++ b/ports/darwin/guts/open.c @@ -9,6 +9,9 @@ struct stat buf = { }; int existed = 1; int save_errno; + + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; #ifdef PSEUDO_FORCE_ASYNCH flags &= ~O_SYNC; #endif diff --git a/ports/linux/guts/__xmknodat.c b/ports/linux/guts/__xmknodat.c index 59b4f2f..0888b8a 100644 --- a/ports/linux/guts/__xmknodat.c +++ b/ports/linux/guts/__xmknodat.c @@ -9,6 +9,9 @@ pseudo_msg_t *msg; struct stat64 buf; + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + /* we don't use underlying call, so _ver is irrelevant to us */ (void) ver; diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c index 8460073..4053549 100644 --- a/ports/linux/guts/openat.c +++ b/ports/linux/guts/openat.c @@ -10,6 +10,9 @@ int existed = 1; int save_errno; + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { errno = ENOSYS; diff --git a/ports/unix/guts/fchmodat.c b/ports/unix/guts/fchmodat.c index 59a92ce..69a953c 100644 --- a/ports/unix/guts/fchmodat.c +++ b/ports/unix/guts/fchmodat.c @@ -8,6 +8,7 @@ */ PSEUDO_STATBUF buf; int save_errno = errno; + static int picky_fchmodat = 0; #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { @@ -15,6 +16,16 @@ return -1; } if (flags & AT_SYMLINK_NOFOLLOW) { + /* Linux, as of this writing, will always reject this. + * GNU tar relies on getting the rejection. To cut down + * on traffic, we check for the failure, and if we saw + * a failure previously, we reject it right away and tell + * the caller to retry. + */ + if (picky_fchmodat) { + errno = ENOTSUP; + return -1; + } rc = base_lstat(path, &buf); } else { rc = base_stat(path, &buf); @@ -50,13 +61,22 @@ /* user bits added so "root" can always access files. */ #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS - /* note: if path was a symlink, and AT_NOFOLLOW_SYMLINKS was + /* note: if path was a symlink, and AT_SYMLINK_NOFOLLOW was * specified, we already bailed previously. */ real_chmod(path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode))); #else - real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode)), flags); + rc = real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode)), flags); + /* AT_SYMLINK_NOFOLLOW isn't supported by fchmodat. GNU tar + * tries to use it anyway, figuring it can just retry if that + * fails. So we want to report that *particular* failure instead + * of doing the fallback. + */ + if (rc == -1 && errno == ENOTSUP && (flags & AT_SYMLINK_NOFOLLOW)) { + picky_fchmodat = 1; + return -1; + } #endif - /* we ignore a failure from underlying fchmod, because pseudo + /* we otherwise ignore failures from underlying fchmod, because pseudo * may believe you are permitted to change modes that the filesystem * doesn't. Note that we also don't need to know whether the * file might be a (pseudo) block device or some such; pseudo diff --git a/ports/unix/guts/mkdirat.c b/ports/unix/guts/mkdirat.c index e846b70..e0b6af9 100644 --- a/ports/unix/guts/mkdirat.c +++ b/ports/unix/guts/mkdirat.c @@ -6,11 +6,14 @@ * wrap_mkdirat(int dirfd, const char *path, mode_t mode) { * int rc = -1; */ + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { errno = ENOSYS; return -1; } + rc = real_mkdir(path, PSEUDO_FS_MODE(mode, 1)); #else rc = real_mkdirat(dirfd, path, PSEUDO_FS_MODE(mode, 1)); diff --git a/ports/unix/guts/mknodat.c b/ports/unix/guts/mknodat.c index 6fd5b42..5d8d47c 100644 --- a/ports/unix/guts/mknodat.c +++ b/ports/unix/guts/mknodat.c @@ -10,6 +10,9 @@ PSEUDO_STATBUF buf; int save_errno = errno; + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { errno = ENOSYS; diff --git a/ports/unix/guts/umask.c b/ports/unix/guts/umask.c new file mode 100644 index 0000000..6b060d3 --- /dev/null +++ b/ports/unix/guts/umask.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * mode_t umask(mode_t mask) + * mode_t rc = 0; + */ + + pseudo_umask = mask; + rc = real_umask(mask); + +/* return rc; + * } + */ diff --git a/ports/unix/wrapfuncs.in b/ports/unix/wrapfuncs.in index 8460a65..e0e9739 100644 --- a/ports/unix/wrapfuncs.in +++ b/ports/unix/wrapfuncs.in @@ -67,3 +67,4 @@ void sync(void); /* async_skip= */ int syncfs(int fd); /* async_skip=0 */ int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags); /* async_skip=0 */ int msync(void *addr, size_t length, int flags); /* async_skip=0 */ +mode_t umask(mode_t mask); diff --git a/pseudo_client.c b/pseudo_client.c index b6d11a6..535c810 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -71,6 +71,8 @@ int pseudo_disabled = 0; int pseudo_allow_fsync = 0; static int pseudo_local_only = 0; +int pseudo_umask = 022; + static char **fd_paths = NULL; static int nfds = 0; static int messages = 0; @@ -219,6 +221,9 @@ pseudo_init_client(void) { if (!pseudo_disabled && !pseudo_inited) { char *pseudo_path = 0; + pseudo_umask = umask(022); + umask(pseudo_umask); + pseudo_path = pseudo_prefix_path(NULL); if (pseudo_prefix_dir_fd == -1) { if (pseudo_path) { diff --git a/pseudo_client.h b/pseudo_client.h index f36a772..5bf820e 100644 --- a/pseudo_client.h +++ b/pseudo_client.h @@ -72,6 +72,8 @@ extern char *pseudo_passwd; extern size_t pseudo_chroot_len; extern int pseudo_nosymlinkexp; +extern int pseudo_umask; + /* Root can read and write files, and enter directories which have no * read, write, or execute permissions. (But can't execute files without * execute permissions!) @@ -85,6 +87,6 @@ extern int pseudo_nosymlinkexp; * None of this will behave very sensibly if umask has 0700 bits in it; * this is a known limitation. */ -#define PSEUDO_FS_MODE(mode, isdir) ((mode) | S_IRUSR | S_IWUSR | ((isdir) ? S_IXUSR : 0)) -#define PSEUDO_DB_MODE(fs_mode, user_mode) (((fs_mode) & ~0700) | ((user_mode & 0700))) +#define PSEUDO_FS_MODE(mode, isdir) (((mode) | S_IRUSR | S_IWUSR | ((isdir) ? S_IXUSR : 0)) & ~(S_IWGRP | S_IWOTH)) +#define PSEUDO_DB_MODE(fs_mode, user_mode) (((fs_mode) & ~0722) | ((user_mode & 0722))) |