Ticket #6750: BugFix-6750-CheckPermissions-in-ext2fs.patch

File BugFix-6750-CheckPermissions-in-ext2fs.patch, 4.9 KB (added by rohityadav, 13 years ago)

Fixes chmod issue in ext2fs (new)

  • src/add-ons/kernel/file_systems/ext2/Inode.cpp

     
    66
    77#include "Inode.h"
    88
    9 #include <fs_cache.h>
    109#include <string.h>
    1110#include <util/AutoLock.h>
     11#include <NodeMonitor.h>
    1212
    1313#include "CachedBlock.h"
    1414#include "DataStream.h"
     
    187187status_t
    188188Inode::CheckPermissions(int accessMode) const
    189189{
    190     uid_t user = geteuid();
    191     gid_t group = getegid();
    192 
    193190    // you never have write access to a read-only volume
    194     if (accessMode & W_OK && fVolume->IsReadOnly())
     191    if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
    195192        return B_READ_ONLY_DEVICE;
    196193
    197     // root users always have full access (but they can't execute files without
    198     // any execute permissions set)
    199     if (user == 0) {
    200         if (!((accessMode & X_OK) != 0 && (Mode() & S_IXUSR) == 0)
    201             || S_ISDIR(Mode()))
    202             return B_OK;
    203     }
    204 
    205     // shift mode bits, to check directly against accessMode
     194    // get node permissions
    206195    mode_t mode = Mode();
    207     if (user == (uid_t)fNode.UserID())
    208         mode >>= 6;
    209     else if (group == (gid_t)fNode.GroupID())
    210         mode >>= 3;
     196    int userPermissions = (mode & S_IRWXU) >> 6;
     197    int groupPermissions = (mode & S_IRWXG) >> 3;
     198    int otherPermissions = mode & S_IRWXO;
    211199
    212     if (accessMode & ~(mode & S_IRWXO))
    213         return B_NOT_ALLOWED;
     200    // get the node permissions for this uid/gid
     201    int permissions = 0;
     202    uid_t uid = geteuid();
     203    gid_t gid = getegid();
    214204
    215     return B_OK;
     205    if (uid == 0) {
     206        // user is root
     207        // root has always read/write permission, but at least one of the
     208        // X bits must be set for execute permission
     209        permissions = userPermissions | groupPermissions | otherPermissions
     210            | R_OK | W_OK;
     211    } else if (uid == (uid_t)fNode.UserID()) {
     212        // user is node owner
     213        permissions = userPermissions;
     214    } else if (gid == (gid_t)fNode.GroupID()) {
     215        // user is in owning group
     216        permissions = groupPermissions;
     217    } else {
     218        // user is one of the others
     219        permissions = otherPermissions;
     220    }
     221
     222    return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
    216223}
    217224
    218225
  • src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp

     
    580580
    581581    Inode* inode = (Inode*)_node->private_node;
    582582
    583     status_t status = inode->CheckPermissions(W_OK);
    584     if (status < B_OK)
    585         return status;
     583    ext2_inode& node = inode->Node();
     584    bool updateTime = false;
     585    uid_t uid = geteuid();
     586   
     587    bool isOwnerOrRoot = uid == 0 || uid == (uid_t)node.UserID();
     588    bool hasWriteAccess = inode->CheckPermissions(W_OK) == B_OK;
    586589
    587590    TRACE("ext2_write_stat: Starting transaction\n");
    588591    Transaction transaction(volume->GetJournal());
    589592    inode->WriteLockInTransaction(transaction);
    590593
    591     bool updateTime = false;
    592 
    593594    if ((mask & B_STAT_SIZE) != 0) {
    594595        if (inode->IsDirectory())
    595596            return B_IS_A_DIRECTORY;
     
    599600        TRACE("ext2_write_stat: Old size: %ld, new size: %ld\n",
    600601            (long)inode->Size(), (long)stat->st_size);
    601602        if (inode->Size() != stat->st_size) {
     603            if (!hasWriteAccess)
     604                return B_NOT_ALLOWED;
    602605            off_t oldSize = inode->Size();
    603606
    604             status = inode->Resize(transaction, stat->st_size);
     607            status_t status = inode->Resize(transaction, stat->st_size);
    605608            if(status != B_OK)
    606609                return status;
    607610
     
    615618        }
    616619    }
    617620
    618     ext2_inode& node = inode->Node();
    619 
    620621    if ((mask & B_STAT_MODE) != 0) {
     622        // only the user or root can do that
     623        if (!isOwnerOrRoot)
     624            return B_NOT_ALLOWED;
    621625        node.UpdateMode(stat->st_mode, S_IUMSK);
    622626        updateTime = true;
    623627    }
    624628
    625629    if ((mask & B_STAT_UID) != 0) {
     630        // only root should be allowed
     631        if (uid != 0)
     632            return B_NOT_ALLOWED;
    626633        node.SetUserID(stat->st_uid);
    627634        updateTime = true;
    628635    }
     636
    629637    if ((mask & B_STAT_GID) != 0) {
     638        // only the user or root can do that
     639        if (!isOwnerOrRoot)
     640            return B_NOT_ALLOWED;
    630641        node.SetGroupID(stat->st_gid);
    631642        updateTime = true;
    632643    }
    633644
    634645    if ((mask & B_STAT_MODIFICATION_TIME) != 0 || updateTime
    635646        || (mask & B_STAT_CHANGE_TIME) != 0) {
     647        // the user or root can do that or any user with write access
     648        if (!isOwnerOrRoot && !hasWriteAccess)
     649            return B_NOT_ALLOWED;
    636650        struct timespec newTimespec = { 0, 0};
    637651
    638652        if ((mask & B_STAT_MODIFICATION_TIME) != 0)
     
    647661
    648662        inode->SetModificationTime(&newTimespec);
    649663    }
    650     if ((mask & B_STAT_CREATION_TIME) != 0)
     664    if ((mask & B_STAT_CREATION_TIME) != 0) {
     665        // the user or root can do that or any user with write access
     666        if (!isOwnerOrRoot && !hasWriteAccess)
     667            return B_NOT_ALLOWED;
    651668        inode->SetCreationTime(&stat->st_crtim);
     669    }
    652670
    653     status = inode->WriteBack(transaction);
     671    status_t status = inode->WriteBack(transaction);
    654672    if (status == B_OK)
    655673        status = transaction.Done();
    656674    if (status == B_OK)