0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <asm/current.h>
0010 #include <linux/anon_inodes.h>
0011 #include <linux/build_bug.h>
0012 #include <linux/capability.h>
0013 #include <linux/compiler_types.h>
0014 #include <linux/dcache.h>
0015 #include <linux/err.h>
0016 #include <linux/errno.h>
0017 #include <linux/fs.h>
0018 #include <linux/limits.h>
0019 #include <linux/mount.h>
0020 #include <linux/path.h>
0021 #include <linux/sched.h>
0022 #include <linux/security.h>
0023 #include <linux/stddef.h>
0024 #include <linux/syscalls.h>
0025 #include <linux/types.h>
0026 #include <linux/uaccess.h>
0027 #include <uapi/linux/landlock.h>
0028
0029 #include "cred.h"
0030 #include "fs.h"
0031 #include "limits.h"
0032 #include "ruleset.h"
0033 #include "setup.h"
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 static __always_inline int
0047 copy_min_struct_from_user(void *const dst, const size_t ksize,
0048 const size_t ksize_min, const void __user *const src,
0049 const size_t usize)
0050 {
0051
0052 BUILD_BUG_ON(!dst);
0053 if (!src)
0054 return -EFAULT;
0055
0056
0057 BUILD_BUG_ON(ksize <= 0);
0058 BUILD_BUG_ON(ksize < ksize_min);
0059 if (usize < ksize_min)
0060 return -EINVAL;
0061 if (usize > PAGE_SIZE)
0062 return -E2BIG;
0063
0064
0065 return copy_struct_from_user(dst, ksize, src, usize);
0066 }
0067
0068
0069
0070
0071
0072
0073 static void build_check_abi(void)
0074 {
0075 struct landlock_ruleset_attr ruleset_attr;
0076 struct landlock_path_beneath_attr path_beneath_attr;
0077 size_t ruleset_size, path_beneath_size;
0078
0079
0080
0081
0082
0083
0084 ruleset_size = sizeof(ruleset_attr.handled_access_fs);
0085 BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size);
0086 BUILD_BUG_ON(sizeof(ruleset_attr) != 8);
0087
0088 path_beneath_size = sizeof(path_beneath_attr.allowed_access);
0089 path_beneath_size += sizeof(path_beneath_attr.parent_fd);
0090 BUILD_BUG_ON(sizeof(path_beneath_attr) != path_beneath_size);
0091 BUILD_BUG_ON(sizeof(path_beneath_attr) != 12);
0092 }
0093
0094
0095
0096 static int fop_ruleset_release(struct inode *const inode,
0097 struct file *const filp)
0098 {
0099 struct landlock_ruleset *ruleset = filp->private_data;
0100
0101 landlock_put_ruleset(ruleset);
0102 return 0;
0103 }
0104
0105 static ssize_t fop_dummy_read(struct file *const filp, char __user *const buf,
0106 const size_t size, loff_t *const ppos)
0107 {
0108
0109 return -EINVAL;
0110 }
0111
0112 static ssize_t fop_dummy_write(struct file *const filp,
0113 const char __user *const buf, const size_t size,
0114 loff_t *const ppos)
0115 {
0116
0117 return -EINVAL;
0118 }
0119
0120
0121
0122
0123
0124
0125
0126 static const struct file_operations ruleset_fops = {
0127 .release = fop_ruleset_release,
0128 .read = fop_dummy_read,
0129 .write = fop_dummy_write,
0130 };
0131
0132 #define LANDLOCK_ABI_VERSION 2
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 SYSCALL_DEFINE3(landlock_create_ruleset,
0158 const struct landlock_ruleset_attr __user *const, attr,
0159 const size_t, size, const __u32, flags)
0160 {
0161 struct landlock_ruleset_attr ruleset_attr;
0162 struct landlock_ruleset *ruleset;
0163 int err, ruleset_fd;
0164
0165
0166 build_check_abi();
0167
0168 if (!landlock_initialized)
0169 return -EOPNOTSUPP;
0170
0171 if (flags) {
0172 if ((flags == LANDLOCK_CREATE_RULESET_VERSION) && !attr &&
0173 !size)
0174 return LANDLOCK_ABI_VERSION;
0175 return -EINVAL;
0176 }
0177
0178
0179 err = copy_min_struct_from_user(&ruleset_attr, sizeof(ruleset_attr),
0180 offsetofend(typeof(ruleset_attr),
0181 handled_access_fs),
0182 attr, size);
0183 if (err)
0184 return err;
0185
0186
0187 if ((ruleset_attr.handled_access_fs | LANDLOCK_MASK_ACCESS_FS) !=
0188 LANDLOCK_MASK_ACCESS_FS)
0189 return -EINVAL;
0190
0191
0192 ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs);
0193 if (IS_ERR(ruleset))
0194 return PTR_ERR(ruleset);
0195
0196
0197 ruleset_fd = anon_inode_getfd("[landlock-ruleset]", &ruleset_fops,
0198 ruleset, O_RDWR | O_CLOEXEC);
0199 if (ruleset_fd < 0)
0200 landlock_put_ruleset(ruleset);
0201 return ruleset_fd;
0202 }
0203
0204
0205
0206
0207
0208 static struct landlock_ruleset *get_ruleset_from_fd(const int fd,
0209 const fmode_t mode)
0210 {
0211 struct fd ruleset_f;
0212 struct landlock_ruleset *ruleset;
0213
0214 ruleset_f = fdget(fd);
0215 if (!ruleset_f.file)
0216 return ERR_PTR(-EBADF);
0217
0218
0219 if (ruleset_f.file->f_op != &ruleset_fops) {
0220 ruleset = ERR_PTR(-EBADFD);
0221 goto out_fdput;
0222 }
0223 if (!(ruleset_f.file->f_mode & mode)) {
0224 ruleset = ERR_PTR(-EPERM);
0225 goto out_fdput;
0226 }
0227 ruleset = ruleset_f.file->private_data;
0228 if (WARN_ON_ONCE(ruleset->num_layers != 1)) {
0229 ruleset = ERR_PTR(-EINVAL);
0230 goto out_fdput;
0231 }
0232 landlock_get_ruleset(ruleset);
0233
0234 out_fdput:
0235 fdput(ruleset_f);
0236 return ruleset;
0237 }
0238
0239
0240
0241
0242
0243
0244 static int get_path_from_fd(const s32 fd, struct path *const path)
0245 {
0246 struct fd f;
0247 int err = 0;
0248
0249 BUILD_BUG_ON(!__same_type(
0250 fd, ((struct landlock_path_beneath_attr *)NULL)->parent_fd));
0251
0252
0253 f = fdget_raw(fd);
0254 if (!f.file)
0255 return -EBADF;
0256
0257
0258
0259
0260
0261 if ((f.file->f_op == &ruleset_fops) ||
0262 (f.file->f_path.mnt->mnt_flags & MNT_INTERNAL) ||
0263 (f.file->f_path.dentry->d_sb->s_flags & SB_NOUSER) ||
0264 d_is_negative(f.file->f_path.dentry) ||
0265 IS_PRIVATE(d_backing_inode(f.file->f_path.dentry))) {
0266 err = -EBADFD;
0267 goto out_fdput;
0268 }
0269 *path = f.file->f_path;
0270 path_get(path);
0271
0272 out_fdput:
0273 fdput(f);
0274 return err;
0275 }
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
0306 const enum landlock_rule_type, rule_type,
0307 const void __user *const, rule_attr, const __u32, flags)
0308 {
0309 struct landlock_path_beneath_attr path_beneath_attr;
0310 struct path path;
0311 struct landlock_ruleset *ruleset;
0312 int res, err;
0313
0314 if (!landlock_initialized)
0315 return -EOPNOTSUPP;
0316
0317
0318 if (flags)
0319 return -EINVAL;
0320
0321
0322 ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_WRITE);
0323 if (IS_ERR(ruleset))
0324 return PTR_ERR(ruleset);
0325
0326 if (rule_type != LANDLOCK_RULE_PATH_BENEATH) {
0327 err = -EINVAL;
0328 goto out_put_ruleset;
0329 }
0330
0331
0332 res = copy_from_user(&path_beneath_attr, rule_attr,
0333 sizeof(path_beneath_attr));
0334 if (res) {
0335 err = -EFAULT;
0336 goto out_put_ruleset;
0337 }
0338
0339
0340
0341
0342
0343 if (!path_beneath_attr.allowed_access) {
0344 err = -ENOMSG;
0345 goto out_put_ruleset;
0346 }
0347
0348
0349
0350
0351 if ((path_beneath_attr.allowed_access | ruleset->fs_access_masks[0]) !=
0352 ruleset->fs_access_masks[0]) {
0353 err = -EINVAL;
0354 goto out_put_ruleset;
0355 }
0356
0357
0358 err = get_path_from_fd(path_beneath_attr.parent_fd, &path);
0359 if (err)
0360 goto out_put_ruleset;
0361
0362
0363 err = landlock_append_fs_rule(ruleset, &path,
0364 path_beneath_attr.allowed_access);
0365 path_put(&path);
0366
0367 out_put_ruleset:
0368 landlock_put_ruleset(ruleset);
0369 return err;
0370 }
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397 SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
0398 flags)
0399 {
0400 struct landlock_ruleset *new_dom, *ruleset;
0401 struct cred *new_cred;
0402 struct landlock_cred_security *new_llcred;
0403 int err;
0404
0405 if (!landlock_initialized)
0406 return -EOPNOTSUPP;
0407
0408
0409
0410
0411
0412 if (!task_no_new_privs(current) &&
0413 !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))
0414 return -EPERM;
0415
0416
0417 if (flags)
0418 return -EINVAL;
0419
0420
0421 ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ);
0422 if (IS_ERR(ruleset))
0423 return PTR_ERR(ruleset);
0424
0425
0426 new_cred = prepare_creds();
0427 if (!new_cred) {
0428 err = -ENOMEM;
0429 goto out_put_ruleset;
0430 }
0431 new_llcred = landlock_cred(new_cred);
0432
0433
0434
0435
0436
0437 new_dom = landlock_merge_ruleset(new_llcred->domain, ruleset);
0438 if (IS_ERR(new_dom)) {
0439 err = PTR_ERR(new_dom);
0440 goto out_put_creds;
0441 }
0442
0443
0444 landlock_put_ruleset(new_llcred->domain);
0445 new_llcred->domain = new_dom;
0446
0447 landlock_put_ruleset(ruleset);
0448 return commit_creds(new_cred);
0449
0450 out_put_creds:
0451 abort_creds(new_cred);
0452
0453 out_put_ruleset:
0454 landlock_put_ruleset(ruleset);
0455 return err;
0456 }