Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   Copyright (C) 2021 Samsung Electronics Co., Ltd.
0004  *   Author(s): Namjae Jeon <linkinjeon@kernel.org>
0005  */
0006 
0007 #include <linux/fs.h>
0008 
0009 #include "glob.h"
0010 #include "ndr.h"
0011 
0012 static inline char *ndr_get_field(struct ndr *n)
0013 {
0014     return n->data + n->offset;
0015 }
0016 
0017 static int try_to_realloc_ndr_blob(struct ndr *n, size_t sz)
0018 {
0019     char *data;
0020 
0021     data = krealloc(n->data, n->offset + sz + 1024, GFP_KERNEL);
0022     if (!data)
0023         return -ENOMEM;
0024 
0025     n->data = data;
0026     n->length += 1024;
0027     memset(n->data + n->offset, 0, 1024);
0028     return 0;
0029 }
0030 
0031 static int ndr_write_int16(struct ndr *n, __u16 value)
0032 {
0033     if (n->length <= n->offset + sizeof(value)) {
0034         int ret;
0035 
0036         ret = try_to_realloc_ndr_blob(n, sizeof(value));
0037         if (ret)
0038             return ret;
0039     }
0040 
0041     *(__le16 *)ndr_get_field(n) = cpu_to_le16(value);
0042     n->offset += sizeof(value);
0043     return 0;
0044 }
0045 
0046 static int ndr_write_int32(struct ndr *n, __u32 value)
0047 {
0048     if (n->length <= n->offset + sizeof(value)) {
0049         int ret;
0050 
0051         ret = try_to_realloc_ndr_blob(n, sizeof(value));
0052         if (ret)
0053             return ret;
0054     }
0055 
0056     *(__le32 *)ndr_get_field(n) = cpu_to_le32(value);
0057     n->offset += sizeof(value);
0058     return 0;
0059 }
0060 
0061 static int ndr_write_int64(struct ndr *n, __u64 value)
0062 {
0063     if (n->length <= n->offset + sizeof(value)) {
0064         int ret;
0065 
0066         ret = try_to_realloc_ndr_blob(n, sizeof(value));
0067         if (ret)
0068             return ret;
0069     }
0070 
0071     *(__le64 *)ndr_get_field(n) = cpu_to_le64(value);
0072     n->offset += sizeof(value);
0073     return 0;
0074 }
0075 
0076 static int ndr_write_bytes(struct ndr *n, void *value, size_t sz)
0077 {
0078     if (n->length <= n->offset + sz) {
0079         int ret;
0080 
0081         ret = try_to_realloc_ndr_blob(n, sz);
0082         if (ret)
0083             return ret;
0084     }
0085 
0086     memcpy(ndr_get_field(n), value, sz);
0087     n->offset += sz;
0088     return 0;
0089 }
0090 
0091 static int ndr_write_string(struct ndr *n, char *value)
0092 {
0093     size_t sz;
0094 
0095     sz = strlen(value) + 1;
0096     if (n->length <= n->offset + sz) {
0097         int ret;
0098 
0099         ret = try_to_realloc_ndr_blob(n, sz);
0100         if (ret)
0101             return ret;
0102     }
0103 
0104     memcpy(ndr_get_field(n), value, sz);
0105     n->offset += sz;
0106     n->offset = ALIGN(n->offset, 2);
0107     return 0;
0108 }
0109 
0110 static int ndr_read_string(struct ndr *n, void *value, size_t sz)
0111 {
0112     int len;
0113 
0114     if (n->offset + sz > n->length)
0115         return -EINVAL;
0116 
0117     len = strnlen(ndr_get_field(n), sz);
0118     if (value)
0119         memcpy(value, ndr_get_field(n), len);
0120     len++;
0121     n->offset += len;
0122     n->offset = ALIGN(n->offset, 2);
0123     return 0;
0124 }
0125 
0126 static int ndr_read_bytes(struct ndr *n, void *value, size_t sz)
0127 {
0128     if (n->offset + sz > n->length)
0129         return -EINVAL;
0130 
0131     if (value)
0132         memcpy(value, ndr_get_field(n), sz);
0133     n->offset += sz;
0134     return 0;
0135 }
0136 
0137 static int ndr_read_int16(struct ndr *n, __u16 *value)
0138 {
0139     if (n->offset + sizeof(__u16) > n->length)
0140         return -EINVAL;
0141 
0142     if (value)
0143         *value = le16_to_cpu(*(__le16 *)ndr_get_field(n));
0144     n->offset += sizeof(__u16);
0145     return 0;
0146 }
0147 
0148 static int ndr_read_int32(struct ndr *n, __u32 *value)
0149 {
0150     if (n->offset + sizeof(__u32) > n->length)
0151         return -EINVAL;
0152 
0153     if (value)
0154         *value = le32_to_cpu(*(__le32 *)ndr_get_field(n));
0155     n->offset += sizeof(__u32);
0156     return 0;
0157 }
0158 
0159 static int ndr_read_int64(struct ndr *n, __u64 *value)
0160 {
0161     if (n->offset + sizeof(__u64) > n->length)
0162         return -EINVAL;
0163 
0164     if (value)
0165         *value = le64_to_cpu(*(__le64 *)ndr_get_field(n));
0166     n->offset += sizeof(__u64);
0167     return 0;
0168 }
0169 
0170 int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
0171 {
0172     char hex_attr[12] = {0};
0173     int ret;
0174 
0175     n->offset = 0;
0176     n->length = 1024;
0177     n->data = kzalloc(n->length, GFP_KERNEL);
0178     if (!n->data)
0179         return -ENOMEM;
0180 
0181     if (da->version == 3) {
0182         snprintf(hex_attr, 10, "0x%x", da->attr);
0183         ret = ndr_write_string(n, hex_attr);
0184     } else {
0185         ret = ndr_write_string(n, "");
0186     }
0187     if (ret)
0188         return ret;
0189 
0190     ret = ndr_write_int16(n, da->version);
0191     if (ret)
0192         return ret;
0193 
0194     ret = ndr_write_int32(n, da->version);
0195     if (ret)
0196         return ret;
0197 
0198     ret = ndr_write_int32(n, da->flags);
0199     if (ret)
0200         return ret;
0201 
0202     ret = ndr_write_int32(n, da->attr);
0203     if (ret)
0204         return ret;
0205 
0206     if (da->version == 3) {
0207         ret = ndr_write_int32(n, da->ea_size);
0208         if (ret)
0209             return ret;
0210         ret = ndr_write_int64(n, da->size);
0211         if (ret)
0212             return ret;
0213         ret = ndr_write_int64(n, da->alloc_size);
0214     } else {
0215         ret = ndr_write_int64(n, da->itime);
0216     }
0217     if (ret)
0218         return ret;
0219 
0220     ret = ndr_write_int64(n, da->create_time);
0221     if (ret)
0222         return ret;
0223 
0224     if (da->version == 3)
0225         ret = ndr_write_int64(n, da->change_time);
0226     return ret;
0227 }
0228 
0229 int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
0230 {
0231     char hex_attr[12];
0232     unsigned int version2;
0233     int ret;
0234 
0235     n->offset = 0;
0236     ret = ndr_read_string(n, hex_attr, sizeof(hex_attr));
0237     if (ret)
0238         return ret;
0239 
0240     ret = ndr_read_int16(n, &da->version);
0241     if (ret)
0242         return ret;
0243 
0244     if (da->version != 3 && da->version != 4) {
0245         pr_err("v%d version is not supported\n", da->version);
0246         return -EINVAL;
0247     }
0248 
0249     ret = ndr_read_int32(n, &version2);
0250     if (ret)
0251         return ret;
0252 
0253     if (da->version != version2) {
0254         pr_err("ndr version mismatched(version: %d, version2: %d)\n",
0255                da->version, version2);
0256         return -EINVAL;
0257     }
0258 
0259     ret = ndr_read_int32(n, NULL);
0260     if (ret)
0261         return ret;
0262 
0263     ret = ndr_read_int32(n, &da->attr);
0264     if (ret)
0265         return ret;
0266 
0267     if (da->version == 4) {
0268         ret = ndr_read_int64(n, &da->itime);
0269         if (ret)
0270             return ret;
0271 
0272         ret = ndr_read_int64(n, &da->create_time);
0273     } else {
0274         ret = ndr_read_int32(n, NULL);
0275         if (ret)
0276             return ret;
0277 
0278         ret = ndr_read_int64(n, NULL);
0279         if (ret)
0280             return ret;
0281 
0282         ret = ndr_read_int64(n, NULL);
0283         if (ret)
0284             return ret;
0285 
0286         ret = ndr_read_int64(n, &da->create_time);
0287         if (ret)
0288             return ret;
0289 
0290         ret = ndr_read_int64(n, NULL);
0291     }
0292 
0293     return ret;
0294 }
0295 
0296 static int ndr_encode_posix_acl_entry(struct ndr *n, struct xattr_smb_acl *acl)
0297 {
0298     int i, ret;
0299 
0300     ret = ndr_write_int32(n, acl->count);
0301     if (ret)
0302         return ret;
0303 
0304     n->offset = ALIGN(n->offset, 8);
0305     ret = ndr_write_int32(n, acl->count);
0306     if (ret)
0307         return ret;
0308 
0309     ret = ndr_write_int32(n, 0);
0310     if (ret)
0311         return ret;
0312 
0313     for (i = 0; i < acl->count; i++) {
0314         n->offset = ALIGN(n->offset, 8);
0315         ret = ndr_write_int16(n, acl->entries[i].type);
0316         if (ret)
0317             return ret;
0318 
0319         ret = ndr_write_int16(n, acl->entries[i].type);
0320         if (ret)
0321             return ret;
0322 
0323         if (acl->entries[i].type == SMB_ACL_USER) {
0324             n->offset = ALIGN(n->offset, 8);
0325             ret = ndr_write_int64(n, acl->entries[i].uid);
0326         } else if (acl->entries[i].type == SMB_ACL_GROUP) {
0327             n->offset = ALIGN(n->offset, 8);
0328             ret = ndr_write_int64(n, acl->entries[i].gid);
0329         }
0330         if (ret)
0331             return ret;
0332 
0333         /* push permission */
0334         ret = ndr_write_int32(n, acl->entries[i].perm);
0335     }
0336 
0337     return ret;
0338 }
0339 
0340 int ndr_encode_posix_acl(struct ndr *n,
0341              struct user_namespace *user_ns,
0342              struct inode *inode,
0343              struct xattr_smb_acl *acl,
0344              struct xattr_smb_acl *def_acl)
0345 {
0346     unsigned int ref_id = 0x00020000;
0347     int ret;
0348 
0349     n->offset = 0;
0350     n->length = 1024;
0351     n->data = kzalloc(n->length, GFP_KERNEL);
0352     if (!n->data)
0353         return -ENOMEM;
0354 
0355     if (acl) {
0356         /* ACL ACCESS */
0357         ret = ndr_write_int32(n, ref_id);
0358         ref_id += 4;
0359     } else {
0360         ret = ndr_write_int32(n, 0);
0361     }
0362     if (ret)
0363         return ret;
0364 
0365     if (def_acl) {
0366         /* DEFAULT ACL ACCESS */
0367         ret = ndr_write_int32(n, ref_id);
0368         ref_id += 4;
0369     } else {
0370         ret = ndr_write_int32(n, 0);
0371     }
0372     if (ret)
0373         return ret;
0374 
0375     ret = ndr_write_int64(n, from_kuid(&init_user_ns, i_uid_into_mnt(user_ns, inode)));
0376     if (ret)
0377         return ret;
0378     ret = ndr_write_int64(n, from_kgid(&init_user_ns, i_gid_into_mnt(user_ns, inode)));
0379     if (ret)
0380         return ret;
0381     ret = ndr_write_int32(n, inode->i_mode);
0382     if (ret)
0383         return ret;
0384 
0385     if (acl) {
0386         ret = ndr_encode_posix_acl_entry(n, acl);
0387         if (def_acl && !ret)
0388             ret = ndr_encode_posix_acl_entry(n, def_acl);
0389     }
0390     return ret;
0391 }
0392 
0393 int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
0394 {
0395     unsigned int ref_id = 0x00020004;
0396     int ret;
0397 
0398     n->offset = 0;
0399     n->length = 2048;
0400     n->data = kzalloc(n->length, GFP_KERNEL);
0401     if (!n->data)
0402         return -ENOMEM;
0403 
0404     ret = ndr_write_int16(n, acl->version);
0405     if (ret)
0406         return ret;
0407 
0408     ret = ndr_write_int32(n, acl->version);
0409     if (ret)
0410         return ret;
0411 
0412     ret = ndr_write_int16(n, 2);
0413     if (ret)
0414         return ret;
0415 
0416     ret = ndr_write_int32(n, ref_id);
0417     if (ret)
0418         return ret;
0419 
0420     /* push hash type and hash 64bytes */
0421     ret = ndr_write_int16(n, acl->hash_type);
0422     if (ret)
0423         return ret;
0424 
0425     ret = ndr_write_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
0426     if (ret)
0427         return ret;
0428 
0429     ret = ndr_write_bytes(n, acl->desc, acl->desc_len);
0430     if (ret)
0431         return ret;
0432 
0433     ret = ndr_write_int64(n, acl->current_time);
0434     if (ret)
0435         return ret;
0436 
0437     ret = ndr_write_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
0438     if (ret)
0439         return ret;
0440 
0441     /* push ndr for security descriptor */
0442     ret = ndr_write_bytes(n, acl->sd_buf, acl->sd_size);
0443     return ret;
0444 }
0445 
0446 int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
0447 {
0448     unsigned int version2;
0449     int ret;
0450 
0451     n->offset = 0;
0452     ret = ndr_read_int16(n, &acl->version);
0453     if (ret)
0454         return ret;
0455     if (acl->version != 4) {
0456         pr_err("v%d version is not supported\n", acl->version);
0457         return -EINVAL;
0458     }
0459 
0460     ret = ndr_read_int32(n, &version2);
0461     if (ret)
0462         return ret;
0463     if (acl->version != version2) {
0464         pr_err("ndr version mismatched(version: %d, version2: %d)\n",
0465                acl->version, version2);
0466         return -EINVAL;
0467     }
0468 
0469     /* Read Level */
0470     ret = ndr_read_int16(n, NULL);
0471     if (ret)
0472         return ret;
0473 
0474     /* Read Ref Id */
0475     ret = ndr_read_int32(n, NULL);
0476     if (ret)
0477         return ret;
0478 
0479     ret = ndr_read_int16(n, &acl->hash_type);
0480     if (ret)
0481         return ret;
0482 
0483     ret = ndr_read_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
0484     if (ret)
0485         return ret;
0486 
0487     ndr_read_bytes(n, acl->desc, 10);
0488     if (strncmp(acl->desc, "posix_acl", 9)) {
0489         pr_err("Invalid acl description : %s\n", acl->desc);
0490         return -EINVAL;
0491     }
0492 
0493     /* Read Time */
0494     ret = ndr_read_int64(n, NULL);
0495     if (ret)
0496         return ret;
0497 
0498     /* Read Posix ACL hash */
0499     ret = ndr_read_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
0500     if (ret)
0501         return ret;
0502 
0503     acl->sd_size = n->length - n->offset;
0504     acl->sd_buf = kzalloc(acl->sd_size, GFP_KERNEL);
0505     if (!acl->sd_buf)
0506         return -ENOMEM;
0507 
0508     ret = ndr_read_bytes(n, acl->sd_buf, acl->sd_size);
0509     return ret;
0510 }