From 8cde3c7982703686f0a5996f9f9b98f1a0d934b3 Mon Sep 17 00:00:00 2001 From: Nicolas Thery Date: Wed, 5 Aug 2009 22:05:00 +0200 Subject: [PATCH] add fchmodat(2) system call Add also its libc_r wrapper and man page. --- lib/libc/sys/Makefile.inc | 2 +- lib/libc/sys/chmod.2 | 44 +++++++++++++++++++++- lib/libc_r/uthread/Makefile.inc | 1 + lib/libc_r/uthread/uthread_fchmodat.c | 54 +++++++++++++++++++++++++++ sys/kern/init_sysent.c | 1 + sys/kern/syscalls.c | 1 + sys/kern/syscalls.master | 2 + sys/kern/vfs_syscalls.c | 25 +++++++++++++ sys/sys/stat.h | 1 + sys/sys/syscall-hide.h | 3 +- sys/sys/syscall.h | 3 +- sys/sys/syscall.mk | 3 +- sys/sys/sysproto.h | 10 +++++ sys/sys/sysunion.h | 1 + 14 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 lib/libc_r/uthread/uthread_fchmodat.c diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 9ee10b0c06..3856fa71d2 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -102,7 +102,7 @@ MLINKS+=brk.2 sbrk.2 MLINKS+=caps_sys_get.2 caps_sys_wait.2 MLINKS+=chdir.2 fchdir.2 MLINKS+=chflags.2 fchflags.2 chflags.2 lchflags.2 -MLINKS+=chmod.2 fchmod.2 chmod.2 lchmod.2 +MLINKS+=chmod.2 fchmod.2 chmod.2 lchmod.2 fchmodat.2 MLINKS+=chown.2 fchown.2 chown.2 lchown.2 MLINKS+=clock_gettime.2 clock_getres.2 clock_gettime.2 clock_settime.2 MLINKS+=dup.2 dup2.2 diff --git a/lib/libc/sys/chmod.2 b/lib/libc/sys/chmod.2 index cff67f65f4..6c3ea36741 100644 --- a/lib/libc/sys/chmod.2 +++ b/lib/libc/sys/chmod.2 @@ -33,13 +33,14 @@ .\" $FreeBSD: src/lib/libc/sys/chmod.2,v 1.16.2.7 2001/12/14 18:34:00 ru Exp $ .\" $DragonFly: src/lib/libc/sys/chmod.2,v 1.4 2006/05/26 19:39:37 swildner Exp $ .\" -.Dd June 4, 1993 +.Dd August 4, 2009 .Dt CHMOD 2 .Os .Sh NAME .Nm chmod , .Nm fchmod , -.Nm lchmod +.Nm lchmod , +.Nm fchmodat .Nd change mode of file .Sh LIBRARY .Lb libc @@ -51,6 +52,8 @@ .Fn fchmod "int fd" "mode_t mode" .Ft int .Fn lchmod "const char *path" "mode_t mode" +.Ft int +.Fn fchmodat "int dirfd" "const char *path" "mode_t mode" "int flags" .Sh DESCRIPTION The file permission bits of the file named specified by .Fa path @@ -78,6 +81,31 @@ function is similar to .Fn chmod but does not follow symbolic links. .Pp +The +.Fn fchmodat +function is equivalent to the +.Fn chmod +or +.Fn lchmod +functions except in the case where the +.Fa path +specifies a relative path. +In this case the file to be opened is determined relative to the directory +associated with the file descriptor +.Fa dirfd +instead of the current working directory. +If +.Fn fchmodat +is passed the special value +.Dv AT_FDCWD +in the +.Fa dirfd +parameter, the current working directory is used +and the behavior is identical to a call to +.Fn chmod +or +.Fn lchmod . +.Pp A mode is created from .Em or'd permission bit masks @@ -157,6 +185,18 @@ This makes the system somewhat more secure by protecting set-user-id (set-group-id) files from remaining set-user-id (set-group-id) if they are modified, at the expense of a degree of compatibility. +.Pp +The values for the +.Fa flags +are constructed by a bitwise-inclusive OR of flags from the following list, +defined in +.In fcntl.h : +.Bl -tag -width indent +.It Dv AT_SYMLINK_NOFOLLOW +If +.Fa path +names a symbolic link, the mode of the symbolic link is changed. +.El .Sh RETURN VALUES .Rv -std .Sh ERRORS diff --git a/lib/libc_r/uthread/Makefile.inc b/lib/libc_r/uthread/Makefile.inc index f40d517831..67298faee5 100644 --- a/lib/libc_r/uthread/Makefile.inc +++ b/lib/libc_r/uthread/Makefile.inc @@ -48,6 +48,7 @@ SRCS+= \ uthread_exit.c \ uthread_fchflags.c \ uthread_fchmod.c \ + uthread_fchmodat.c \ uthread_fchown.c \ uthread_fcntl.c \ uthread_fd.c \ diff --git a/lib/libc_r/uthread/uthread_fchmodat.c b/lib/libc_r/uthread/uthread_fchmodat.c new file mode 100644 index 0000000000..ed0ea6c5c0 --- /dev/null +++ b/lib/libc_r/uthread/uthread_fchmodat.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Nicolas Thery + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly$ + */ + +#include +#include +#include +#include "pthread_private.h" + +int +_fchmodat(int fd, const char *path, mode_t mode, int flags) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + ret = __sys_fchmodat(fd, path, mode, flags); + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} + +__strong_reference(_fchmodat, fchmodat); diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 692a92a90c..6d69ef665f 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -539,4 +539,5 @@ struct sysent sysent[] = { { AS(getvfsstat_args), (sy_call_t *)sys_getvfsstat }, /* 503 = getvfsstat */ { AS(openat_args), (sy_call_t *)sys_openat }, /* 504 = openat */ { AS(fstatat_args), (sy_call_t *)sys_fstatat }, /* 505 = fstatat */ + { AS(fchmodat_args), (sy_call_t *)sys_fchmodat }, /* 506 = fchmodat */ }; diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 956dede005..007e6a967d 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -513,4 +513,5 @@ const char *syscallnames[] = { "getvfsstat", /* 503 = getvfsstat */ "openat", /* 504 = openat */ "fstatat", /* 505 = fstatat */ + "fchmodat", /* 506 = fchmodat */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 24e4d6d6d2..83fe3f1e0f 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -694,3 +694,5 @@ ; XXX man page says `mode_t mode'. 505 STD POSIX { int fstatat(int fd, char *path, \ struct stat *sb, int flags); } +506 STD POSIX { int fchmodat(int fd, char *path, int mode, \ + int flags); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 40207fe1a6..83bf5cf478 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -2783,6 +2783,31 @@ sys_fchmod(struct fchmod_args *uap) return (error); } +/* + * fchmodat_args(char *path, int mode) + * + * Change mode of a file pointed to by fd/path. + */ +int +sys_fchmodat(struct fchmodat_args *uap) +{ + struct nlookupdata nd; + struct file *fp; + int error; + int flags; + + if (uap->flags & ~_AT_SYMLINK_MASK) + return (EINVAL); + flags = (uap->flags & AT_SYMLINK_NOFOLLOW) ? 0 : NLC_FOLLOW; + + error = nlookup_init_at(&nd, &fp, uap->fd, uap->path, + UIO_USERSPACE, flags); + if (error == 0) + error = kern_chmod(&nd, uap->mode); + nlookup_done_at(&nd, fp); + return (error); +} + static int setfown(struct vnode *vp, uid_t uid, gid_t gid) { diff --git a/sys/sys/stat.h b/sys/sys/stat.h index ce927f597e..b9bf448506 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -208,6 +208,7 @@ struct stat { __BEGIN_DECLS int chmod (const char *, mode_t); +int fchmodat (int, const char *, mode_t, int); int fstat (int, struct stat *); int fstatat (int, const char *, struct stat *, int); int mkdir (const char *, mode_t); diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h index 189273ba9d..cb22bbddbb 100644 --- a/sys/sys/syscall-hide.h +++ b/sys/sys/syscall-hide.h @@ -334,5 +334,6 @@ HIDE_BSD(statvfs) HIDE_BSD(fstatvfs) HIDE_BSD(fhstatvfs) HIDE_BSD(getvfsstat) -HIDE_BSD(openat) +HIDE_POSIX(openat) HIDE_POSIX(fstatat) +HIDE_POSIX(fchmodat) diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index f39efb9504..ff73c93fd3 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -347,4 +347,5 @@ #define SYS_getvfsstat 503 #define SYS_openat 504 #define SYS_fstatat 505 -#define SYS_MAXSYSCALL 506 +#define SYS_fchmodat 506 +#define SYS_MAXSYSCALL 507 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index c8c645669e..e027afdc3d 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -287,4 +287,5 @@ MIASM = \ fhstatvfs.o \ getvfsstat.o \ openat.o \ - fstatat.o + fstatat.o \ + fchmodat.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 0442581984..05db2a2f5b 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -2177,6 +2177,15 @@ struct fstatat_args { struct stat * sb; char sb_[PAD_(struct stat *)]; int flags; char flags_[PAD_(int)]; }; +struct fchmodat_args { +#ifdef _KERNEL + struct sysmsg sysmsg; +#endif + int fd; char fd_[PAD_(int)]; + char * path; char path_[PAD_(char *)]; + int mode; char mode_[PAD_(int)]; + int flags; char flags_[PAD_(int)]; +}; #ifdef COMPAT_43 @@ -2765,6 +2774,7 @@ int sys_fhstatvfs (struct fhstatvfs_args *); int sys_getvfsstat (struct getvfsstat_args *); int sys_openat (struct openat_args *); int sys_fstatat (struct fstatat_args *); +int sys_fchmodat (struct fchmodat_args *); #endif /* !_SYS_SYSPROTO_H_ */ #undef PAD_ diff --git a/sys/sys/sysunion.h b/sys/sys/sysunion.h index f022dbaff4..f2bc2fe56a 100644 --- a/sys/sys/sysunion.h +++ b/sys/sys/sysunion.h @@ -392,4 +392,5 @@ union sysunion { struct getvfsstat_args getvfsstat; struct openat_args openat; struct fstatat_args fstatat; + struct fchmodat_args fchmodat; }; -- 2.41.0