int locks_verify_locked(struct inode *inode) { /* Candidates for mandatory locking have the setgid bit set * but no group execute bit - an otherwise meaningless combination. */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) return (locks_mandatory_locked(inode)); return (0); }
int locks_verify_area(int read_write, struct inode *inode, struct file *filp, unsigned int offset, unsigned int count) { /* Candidates for mandatory locking have the setgid bit set * but no group execute bit - an otherwise meaningless combination. */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) return (locks_mandatory_area(read_write, inode, filp, offset, count)); return (0); }
/* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). * It also emulates flock() in a pretty broken way for older C * libraries. */ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) { int error; struct file *filp; struct file_lock file_lock; struct flock flock; struct inode *inode; /* Get arguments and validate them ... */ if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) return (-EBADF); error = verify_area(VERIFY_READ, l, sizeof(*l)); if (error) return (error); if (!(inode = filp->f_inode)) return (-EINVAL); /* * This might block, so we do it before checking the inode. */ memcpy_fromfs(&flock, l, sizeof(flock)); /* Don't allow mandatory locks on files that may be memory mapped * and shared. */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && inode->i_mmap) { struct vm_area_struct *vma = inode->i_mmap; do { if (vma->vm_flags & VM_MAYSHARE) return (-EAGAIN); vma = vma->vm_next_share; } while (vma != inode->i_mmap); } if (!posix_make_lock(filp, &file_lock, &flock)) return (-EINVAL); switch (flock.l_type) { case F_RDLCK: if (!(filp->f_mode & 1)) return (-EBADF); break; case F_WRLCK: if (!(filp->f_mode & 2)) return (-EBADF); break; case F_UNLCK: break; case F_SHLCK: case F_EXLCK: #if 1 /* warn a bit for now, but don't overdo it */ { static int count = 0; if (!count) { count=1; printk(KERN_WARNING "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n", current->pid, current->comm); } } #endif if (!(filp->f_mode & 3)) return (-EBADF); break; default: return (-EINVAL); } return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); }
/* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) { struct file *filp; struct file_lock file_lock; struct flock flock; struct dentry * dentry; struct inode *inode; int error; /* * This might block, so we do it before checking the inode. */ error = -EFAULT; if (copy_from_user(&flock, l, sizeof(flock))) goto out; /* Get arguments and validate them ... */ error = -EBADF; filp = fget(fd); if (!filp) goto out; error = -EINVAL; if (!(dentry = filp->f_dentry)) goto out_putf; if (!(inode = dentry->d_inode)) goto out_putf; /* Don't allow mandatory locks on files that may be memory mapped * and shared. */ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && inode->i_mmap) { struct vm_area_struct *vma = inode->i_mmap; error = -EAGAIN; do { if (vma->vm_flags & VM_MAYSHARE) goto out_putf; } while ((vma = vma->vm_next_share) != NULL); } error = -EINVAL; if (!posix_make_lock(filp, &file_lock, &flock)) goto out_putf; error = -EBADF; switch (flock.l_type) { case F_RDLCK: if (!(filp->f_mode & FMODE_READ)) goto out_putf; break; case F_WRLCK: if (!(filp->f_mode & FMODE_WRITE)) goto out_putf; break; case F_UNLCK: break; case F_SHLCK: case F_EXLCK: #ifdef __sparc__ /* warn a bit for now, but don't overdo it */ { static int count = 0; if (!count) { count=1; printk(KERN_WARNING "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n", current->pid, current->comm); } } if (!(filp->f_mode & 3)) goto out_putf; break; #endif default: error = -EINVAL; goto out_putf; } if (filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, &file_lock); if (error < 0) goto out_putf; } error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW); out_putf: fput(filp); out: return error; }