fs/ntfs3: Fix slab-out-of-bounds in r_page
[platform/kernel/linux-rpi.git] / fs / ntfs3 / fslog.c
index 06492f0..20abdb2 100644 (file)
@@ -1132,7 +1132,7 @@ static int read_log_page(struct ntfs_log *log, u32 vbo,
                return -EINVAL;
 
        if (!*buffer) {
-               to_free = kmalloc(bytes, GFP_NOFS);
+               to_free = kmalloc(log->page_size, GFP_NOFS);
                if (!to_free)
                        return -ENOMEM;
                *buffer = to_free;
@@ -1180,12 +1180,7 @@ static int log_read_rst(struct ntfs_log *log, u32 l_size, bool first,
                        struct restart_info *info)
 {
        u32 skip, vbo;
-       struct RESTART_HDR *r_page = kmalloc(DefaultLogPageSize, GFP_NOFS);
-
-       if (!r_page)
-               return -ENOMEM;
-
-       memset(info, 0, sizeof(struct restart_info));
+       struct RESTART_HDR *r_page = NULL;
 
        /* Determine which restart area we are looking for. */
        if (first) {
@@ -1199,7 +1194,6 @@ static int log_read_rst(struct ntfs_log *log, u32 l_size, bool first,
        /* Loop continuously until we succeed. */
        for (; vbo < l_size; vbo = 2 * vbo + skip, skip = 0) {
                bool usa_error;
-               u32 sys_page_size;
                bool brst, bchk;
                struct RESTART_AREA *ra;
 
@@ -1253,24 +1247,6 @@ static int log_read_rst(struct ntfs_log *log, u32 l_size, bool first,
                        goto check_result;
                }
 
-               /* Read the entire restart area. */
-               sys_page_size = le32_to_cpu(r_page->sys_page_size);
-               if (DefaultLogPageSize != sys_page_size) {
-                       kfree(r_page);
-                       r_page = kzalloc(sys_page_size, GFP_NOFS);
-                       if (!r_page)
-                               return -ENOMEM;
-
-                       if (read_log_page(log, vbo,
-                                         (struct RECORD_PAGE_HDR **)&r_page,
-                                         &usa_error)) {
-                               /* Ignore any errors. */
-                               kfree(r_page);
-                               r_page = NULL;
-                               continue;
-                       }
-               }
-
                if (is_client_area_valid(r_page, usa_error)) {
                        info->valid_page = true;
                        ra = Add2Ptr(r_page, le16_to_cpu(r_page->ra_off));
@@ -2729,6 +2705,9 @@ static inline bool check_attr(const struct MFT_REC *rec,
                        return false;
                }
 
+               if (run_off > asize)
+                       return false;
+
                if (run_unpack(NULL, sbi, 0, svcn, evcn, svcn,
                               Add2Ptr(attr, run_off), asize - run_off) < 0) {
                        return false;
@@ -3791,10 +3770,11 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
        if (!log)
                return -ENOMEM;
 
+       memset(&rst_info, 0, sizeof(struct restart_info));
+
        log->ni = ni;
        log->l_size = l_size;
        log->one_page_buf = kmalloc(page_size, GFP_NOFS);
-
        if (!log->one_page_buf) {
                err = -ENOMEM;
                goto out;
@@ -3842,6 +3822,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
        if (rst_info.vbo)
                goto check_restart_area;
 
+       memset(&rst_info2, 0, sizeof(struct restart_info));
        err = log_read_rst(log, l_size, false, &rst_info2);
 
        /* Determine which restart area to use. */
@@ -4085,8 +4066,10 @@ process_log:
                if (client == LFS_NO_CLIENT_LE) {
                        /* Insert "NTFS" client LogFile. */
                        client = ra->client_idx[0];
-                       if (client == LFS_NO_CLIENT_LE)
-                               return -EINVAL;
+                       if (client == LFS_NO_CLIENT_LE) {
+                               err = -EINVAL;
+                               goto out;
+                       }
 
                        t16 = le16_to_cpu(client);
                        cr = ca + t16;
@@ -4767,6 +4750,12 @@ fake_attr:
                u16 roff = le16_to_cpu(attr->nres.run_off);
                CLST svcn = le64_to_cpu(attr->nres.svcn);
 
+               if (roff > t32) {
+                       kfree(oa->attr);
+                       oa->attr = NULL;
+                       goto fake_attr;
+               }
+
                err = run_unpack(&oa->run0, sbi, inode->i_ino, svcn,
                                 le64_to_cpu(attr->nres.evcn), svcn,
                                 Add2Ptr(attr, roff), t32 - roff);
@@ -5055,7 +5044,7 @@ undo_action_next:
                goto add_allocated_vcns;
 
        vcn = le64_to_cpu(lrh->target_vcn);
-       vcn &= ~(log->clst_per_page - 1);
+       vcn &= ~(u64)(log->clst_per_page - 1);
 
 add_allocated_vcns:
        for (i = 0, vcn = le64_to_cpu(lrh->target_vcn),