11da177e4SLinus Torvalds /* xfrm_user.c: User interface to configure xfrm engine. 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Copyright (C) 2002 David S. Miller (davem@redhat.com) 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Changes: 61da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 71da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 81da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 91da177e4SLinus Torvalds * IPv6 support 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 139409f38aSHerbert Xu #include <linux/crypto.h> 141da177e4SLinus Torvalds #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/types.h> 171da177e4SLinus Torvalds #include <linux/slab.h> 181da177e4SLinus Torvalds #include <linux/socket.h> 191da177e4SLinus Torvalds #include <linux/string.h> 201da177e4SLinus Torvalds #include <linux/net.h> 211da177e4SLinus Torvalds #include <linux/skbuff.h> 221da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 231da177e4SLinus Torvalds #include <linux/ipsec.h> 241da177e4SLinus Torvalds #include <linux/init.h> 251da177e4SLinus Torvalds #include <linux/security.h> 261da177e4SLinus Torvalds #include <net/sock.h> 271da177e4SLinus Torvalds #include <net/xfrm.h> 2888fc2c84SThomas Graf #include <net/netlink.h> 29fa6dd8a2SNicolas Dichtel #include <net/ah.h> 307c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 31dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 32e23c7194SMasahide NAKAMURA #include <linux/in6.h> 33e23c7194SMasahide NAKAMURA #endif 34e33d4f13SSowmini Varadhan #include <asm/unaligned.h> 351da177e4SLinus Torvalds 365424f32eSThomas Graf static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) 371da177e4SLinus Torvalds { 385424f32eSThomas Graf struct nlattr *rt = attrs[type]; 391da177e4SLinus Torvalds struct xfrm_algo *algp; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds if (!rt) 421da177e4SLinus Torvalds return 0; 431da177e4SLinus Torvalds 445424f32eSThomas Graf algp = nla_data(rt); 450f99be0dSEric Dumazet if (nla_len(rt) < xfrm_alg_len(algp)) 4631c26852SHerbert Xu return -EINVAL; 4731c26852SHerbert Xu 481da177e4SLinus Torvalds switch (type) { 491da177e4SLinus Torvalds case XFRMA_ALG_AUTH: 501da177e4SLinus Torvalds case XFRMA_ALG_CRYPT: 511da177e4SLinus Torvalds case XFRMA_ALG_COMP: 521da177e4SLinus Torvalds break; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds default: 551da177e4SLinus Torvalds return -EINVAL; 563ff50b79SStephen Hemminger } 571da177e4SLinus Torvalds 58*633439f5SHerbert Xu algp->alg_name[sizeof(algp->alg_name) - 1] = '\0'; 591da177e4SLinus Torvalds return 0; 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 624447bb33SMartin Willi static int verify_auth_trunc(struct nlattr **attrs) 634447bb33SMartin Willi { 644447bb33SMartin Willi struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC]; 654447bb33SMartin Willi struct xfrm_algo_auth *algp; 664447bb33SMartin Willi 674447bb33SMartin Willi if (!rt) 684447bb33SMartin Willi return 0; 694447bb33SMartin Willi 704447bb33SMartin Willi algp = nla_data(rt); 714447bb33SMartin Willi if (nla_len(rt) < xfrm_alg_auth_len(algp)) 724447bb33SMartin Willi return -EINVAL; 734447bb33SMartin Willi 74*633439f5SHerbert Xu algp->alg_name[sizeof(algp->alg_name) - 1] = '\0'; 754447bb33SMartin Willi return 0; 764447bb33SMartin Willi } 774447bb33SMartin Willi 781a6509d9SHerbert Xu static int verify_aead(struct nlattr **attrs) 791a6509d9SHerbert Xu { 801a6509d9SHerbert Xu struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; 811a6509d9SHerbert Xu struct xfrm_algo_aead *algp; 821a6509d9SHerbert Xu 831a6509d9SHerbert Xu if (!rt) 841a6509d9SHerbert Xu return 0; 851a6509d9SHerbert Xu 861a6509d9SHerbert Xu algp = nla_data(rt); 871a6509d9SHerbert Xu if (nla_len(rt) < aead_len(algp)) 881a6509d9SHerbert Xu return -EINVAL; 891a6509d9SHerbert Xu 90*633439f5SHerbert Xu algp->alg_name[sizeof(algp->alg_name) - 1] = '\0'; 911a6509d9SHerbert Xu return 0; 921a6509d9SHerbert Xu } 931a6509d9SHerbert Xu 945424f32eSThomas Graf static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, 95eb2971b6SMasahide NAKAMURA xfrm_address_t **addrp) 96eb2971b6SMasahide NAKAMURA { 975424f32eSThomas Graf struct nlattr *rt = attrs[type]; 98eb2971b6SMasahide NAKAMURA 99cf5cb79fSThomas Graf if (rt && addrp) 1005424f32eSThomas Graf *addrp = nla_data(rt); 101eb2971b6SMasahide NAKAMURA } 102df71837dSTrent Jaeger 1035424f32eSThomas Graf static inline int verify_sec_ctx_len(struct nlattr **attrs) 104df71837dSTrent Jaeger { 1055424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 106df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 107df71837dSTrent Jaeger 108df71837dSTrent Jaeger if (!rt) 109df71837dSTrent Jaeger return 0; 110df71837dSTrent Jaeger 1115424f32eSThomas Graf uctx = nla_data(rt); 112cf5cb79fSThomas Graf if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len)) 113df71837dSTrent Jaeger return -EINVAL; 114df71837dSTrent Jaeger 115df71837dSTrent Jaeger return 0; 116df71837dSTrent Jaeger } 117df71837dSTrent Jaeger 118d8647b79SSteffen Klassert static inline int verify_replay(struct xfrm_usersa_info *p, 119d8647b79SSteffen Klassert struct nlattr **attrs) 120d8647b79SSteffen Klassert { 121d8647b79SSteffen Klassert struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; 122ecd79187SMathias Krause struct xfrm_replay_state_esn *rs; 123d8647b79SSteffen Klassert 124ecd79187SMathias Krause if (p->flags & XFRM_STATE_ESN) { 125ecd79187SMathias Krause if (!rt) 1267833aa05SSteffen Klassert return -EINVAL; 1277833aa05SSteffen Klassert 128ecd79187SMathias Krause rs = nla_data(rt); 129ecd79187SMathias Krause 130ecd79187SMathias Krause if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) 131ecd79187SMathias Krause return -EINVAL; 132ecd79187SMathias Krause 133ecd79187SMathias Krause if (nla_len(rt) < xfrm_replay_state_esn_len(rs) && 134ecd79187SMathias Krause nla_len(rt) != sizeof(*rs)) 135ecd79187SMathias Krause return -EINVAL; 136ecd79187SMathias Krause } 137ecd79187SMathias Krause 138d8647b79SSteffen Klassert if (!rt) 139d8647b79SSteffen Klassert return 0; 140d8647b79SSteffen Klassert 14101714109SFan Du /* As only ESP and AH support ESN feature. */ 14201714109SFan Du if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH)) 14302aadf72SSteffen Klassert return -EINVAL; 14402aadf72SSteffen Klassert 145d8647b79SSteffen Klassert if (p->replay_window != 0) 146d8647b79SSteffen Klassert return -EINVAL; 147d8647b79SSteffen Klassert 148d8647b79SSteffen Klassert return 0; 149d8647b79SSteffen Klassert } 150df71837dSTrent Jaeger 1511da177e4SLinus Torvalds static int verify_newsa_info(struct xfrm_usersa_info *p, 1525424f32eSThomas Graf struct nlattr **attrs) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds int err; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds err = -EINVAL; 1571da177e4SLinus Torvalds switch (p->family) { 1581da177e4SLinus Torvalds case AF_INET: 1591da177e4SLinus Torvalds break; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds case AF_INET6: 162dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 1631da177e4SLinus Torvalds break; 1641da177e4SLinus Torvalds #else 1651da177e4SLinus Torvalds err = -EAFNOSUPPORT; 1661da177e4SLinus Torvalds goto out; 1671da177e4SLinus Torvalds #endif 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds default: 1701da177e4SLinus Torvalds goto out; 1713ff50b79SStephen Hemminger } 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds err = -EINVAL; 1741da177e4SLinus Torvalds switch (p->id.proto) { 1751da177e4SLinus Torvalds case IPPROTO_AH: 1764447bb33SMartin Willi if ((!attrs[XFRMA_ALG_AUTH] && 1774447bb33SMartin Willi !attrs[XFRMA_ALG_AUTH_TRUNC]) || 1781a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD] || 17935a7aa08SThomas Graf attrs[XFRMA_ALG_CRYPT] || 18035d2856bSMartin Willi attrs[XFRMA_ALG_COMP] || 181a0e5ef53STobias Brunner attrs[XFRMA_TFCPAD]) 1821da177e4SLinus Torvalds goto out; 1831da177e4SLinus Torvalds break; 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds case IPPROTO_ESP: 1861a6509d9SHerbert Xu if (attrs[XFRMA_ALG_COMP]) 1871a6509d9SHerbert Xu goto out; 1881a6509d9SHerbert Xu if (!attrs[XFRMA_ALG_AUTH] && 1894447bb33SMartin Willi !attrs[XFRMA_ALG_AUTH_TRUNC] && 1901a6509d9SHerbert Xu !attrs[XFRMA_ALG_CRYPT] && 1911a6509d9SHerbert Xu !attrs[XFRMA_ALG_AEAD]) 1921a6509d9SHerbert Xu goto out; 1931a6509d9SHerbert Xu if ((attrs[XFRMA_ALG_AUTH] || 1944447bb33SMartin Willi attrs[XFRMA_ALG_AUTH_TRUNC] || 1951a6509d9SHerbert Xu attrs[XFRMA_ALG_CRYPT]) && 1961a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD]) 1971da177e4SLinus Torvalds goto out; 19835d2856bSMartin Willi if (attrs[XFRMA_TFCPAD] && 19935d2856bSMartin Willi p->mode != XFRM_MODE_TUNNEL) 20035d2856bSMartin Willi goto out; 2011da177e4SLinus Torvalds break; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds case IPPROTO_COMP: 20435a7aa08SThomas Graf if (!attrs[XFRMA_ALG_COMP] || 2051a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD] || 20635a7aa08SThomas Graf attrs[XFRMA_ALG_AUTH] || 2074447bb33SMartin Willi attrs[XFRMA_ALG_AUTH_TRUNC] || 20835d2856bSMartin Willi attrs[XFRMA_ALG_CRYPT] || 209a0e5ef53STobias Brunner attrs[XFRMA_TFCPAD] || 210a0e5ef53STobias Brunner (ntohl(p->id.spi) >= 0x10000)) 2111da177e4SLinus Torvalds goto out; 2121da177e4SLinus Torvalds break; 2131da177e4SLinus Torvalds 214dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 215e23c7194SMasahide NAKAMURA case IPPROTO_DSTOPTS: 216e23c7194SMasahide NAKAMURA case IPPROTO_ROUTING: 21735a7aa08SThomas Graf if (attrs[XFRMA_ALG_COMP] || 21835a7aa08SThomas Graf attrs[XFRMA_ALG_AUTH] || 2194447bb33SMartin Willi attrs[XFRMA_ALG_AUTH_TRUNC] || 2201a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD] || 22135a7aa08SThomas Graf attrs[XFRMA_ALG_CRYPT] || 22235a7aa08SThomas Graf attrs[XFRMA_ENCAP] || 22335a7aa08SThomas Graf attrs[XFRMA_SEC_CTX] || 22435d2856bSMartin Willi attrs[XFRMA_TFCPAD] || 22535a7aa08SThomas Graf !attrs[XFRMA_COADDR]) 226e23c7194SMasahide NAKAMURA goto out; 227e23c7194SMasahide NAKAMURA break; 228e23c7194SMasahide NAKAMURA #endif 229e23c7194SMasahide NAKAMURA 2301da177e4SLinus Torvalds default: 2311da177e4SLinus Torvalds goto out; 2323ff50b79SStephen Hemminger } 2331da177e4SLinus Torvalds 2341a6509d9SHerbert Xu if ((err = verify_aead(attrs))) 2351a6509d9SHerbert Xu goto out; 2364447bb33SMartin Willi if ((err = verify_auth_trunc(attrs))) 2374447bb33SMartin Willi goto out; 23835a7aa08SThomas Graf if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) 2391da177e4SLinus Torvalds goto out; 24035a7aa08SThomas Graf if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) 2411da177e4SLinus Torvalds goto out; 24235a7aa08SThomas Graf if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP))) 2431da177e4SLinus Torvalds goto out; 24435a7aa08SThomas Graf if ((err = verify_sec_ctx_len(attrs))) 245df71837dSTrent Jaeger goto out; 246d8647b79SSteffen Klassert if ((err = verify_replay(p, attrs))) 247d8647b79SSteffen Klassert goto out; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds err = -EINVAL; 2501da177e4SLinus Torvalds switch (p->mode) { 2517e49e6deSMasahide NAKAMURA case XFRM_MODE_TRANSPORT: 2527e49e6deSMasahide NAKAMURA case XFRM_MODE_TUNNEL: 253060f02a3SNoriaki TAKAMIYA case XFRM_MODE_ROUTEOPTIMIZATION: 2540a69452cSDiego Beltrami case XFRM_MODE_BEET: 2551da177e4SLinus Torvalds break; 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds default: 2581da177e4SLinus Torvalds goto out; 2593ff50b79SStephen Hemminger } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds err = 0; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds out: 2641da177e4SLinus Torvalds return err; 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, 2686f2f19edSDavid S. Miller struct xfrm_algo_desc *(*get_byname)(const char *, int), 2695424f32eSThomas Graf struct nlattr *rta) 2701da177e4SLinus Torvalds { 2711da177e4SLinus Torvalds struct xfrm_algo *p, *ualg; 2721da177e4SLinus Torvalds struct xfrm_algo_desc *algo; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds if (!rta) 2751da177e4SLinus Torvalds return 0; 2761da177e4SLinus Torvalds 2775424f32eSThomas Graf ualg = nla_data(rta); 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds algo = get_byname(ualg->alg_name, 1); 2801da177e4SLinus Torvalds if (!algo) 2811da177e4SLinus Torvalds return -ENOSYS; 2821da177e4SLinus Torvalds *props = algo->desc.sadb_alg_id; 2831da177e4SLinus Torvalds 2840f99be0dSEric Dumazet p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL); 2851da177e4SLinus Torvalds if (!p) 2861da177e4SLinus Torvalds return -ENOMEM; 2871da177e4SLinus Torvalds 28804ff1260SHerbert Xu strcpy(p->alg_name, algo->name); 2891da177e4SLinus Torvalds *algpp = p; 2901da177e4SLinus Torvalds return 0; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 29369b0137fSHerbert Xu static int attach_crypt(struct xfrm_state *x, struct nlattr *rta) 29469b0137fSHerbert Xu { 29569b0137fSHerbert Xu struct xfrm_algo *p, *ualg; 29669b0137fSHerbert Xu struct xfrm_algo_desc *algo; 29769b0137fSHerbert Xu 29869b0137fSHerbert Xu if (!rta) 29969b0137fSHerbert Xu return 0; 30069b0137fSHerbert Xu 30169b0137fSHerbert Xu ualg = nla_data(rta); 30269b0137fSHerbert Xu 30369b0137fSHerbert Xu algo = xfrm_ealg_get_byname(ualg->alg_name, 1); 30469b0137fSHerbert Xu if (!algo) 30569b0137fSHerbert Xu return -ENOSYS; 30669b0137fSHerbert Xu x->props.ealgo = algo->desc.sadb_alg_id; 30769b0137fSHerbert Xu 30869b0137fSHerbert Xu p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL); 30969b0137fSHerbert Xu if (!p) 31069b0137fSHerbert Xu return -ENOMEM; 31169b0137fSHerbert Xu 31269b0137fSHerbert Xu strcpy(p->alg_name, algo->name); 31369b0137fSHerbert Xu x->ealg = p; 31469b0137fSHerbert Xu x->geniv = algo->uinfo.encr.geniv; 31569b0137fSHerbert Xu return 0; 31669b0137fSHerbert Xu } 31769b0137fSHerbert Xu 3184447bb33SMartin Willi static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props, 3194447bb33SMartin Willi struct nlattr *rta) 3204447bb33SMartin Willi { 3214447bb33SMartin Willi struct xfrm_algo *ualg; 3224447bb33SMartin Willi struct xfrm_algo_auth *p; 3234447bb33SMartin Willi struct xfrm_algo_desc *algo; 3244447bb33SMartin Willi 3254447bb33SMartin Willi if (!rta) 3264447bb33SMartin Willi return 0; 3274447bb33SMartin Willi 3284447bb33SMartin Willi ualg = nla_data(rta); 3294447bb33SMartin Willi 3304447bb33SMartin Willi algo = xfrm_aalg_get_byname(ualg->alg_name, 1); 3314447bb33SMartin Willi if (!algo) 3324447bb33SMartin Willi return -ENOSYS; 3334447bb33SMartin Willi *props = algo->desc.sadb_alg_id; 3344447bb33SMartin Willi 3354447bb33SMartin Willi p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL); 3364447bb33SMartin Willi if (!p) 3374447bb33SMartin Willi return -ENOMEM; 3384447bb33SMartin Willi 3394447bb33SMartin Willi strcpy(p->alg_name, algo->name); 3404447bb33SMartin Willi p->alg_key_len = ualg->alg_key_len; 3414447bb33SMartin Willi p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; 3424447bb33SMartin Willi memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8); 3434447bb33SMartin Willi 3444447bb33SMartin Willi *algpp = p; 3454447bb33SMartin Willi return 0; 3464447bb33SMartin Willi } 3474447bb33SMartin Willi 3484447bb33SMartin Willi static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props, 3494447bb33SMartin Willi struct nlattr *rta) 3504447bb33SMartin Willi { 3514447bb33SMartin Willi struct xfrm_algo_auth *p, *ualg; 3524447bb33SMartin Willi struct xfrm_algo_desc *algo; 3534447bb33SMartin Willi 3544447bb33SMartin Willi if (!rta) 3554447bb33SMartin Willi return 0; 3564447bb33SMartin Willi 3574447bb33SMartin Willi ualg = nla_data(rta); 3584447bb33SMartin Willi 3594447bb33SMartin Willi algo = xfrm_aalg_get_byname(ualg->alg_name, 1); 3604447bb33SMartin Willi if (!algo) 3614447bb33SMartin Willi return -ENOSYS; 362689f1c9dSHerbert Xu if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits) 3634447bb33SMartin Willi return -EINVAL; 3644447bb33SMartin Willi *props = algo->desc.sadb_alg_id; 3654447bb33SMartin Willi 3664447bb33SMartin Willi p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL); 3674447bb33SMartin Willi if (!p) 3684447bb33SMartin Willi return -ENOMEM; 3694447bb33SMartin Willi 3704447bb33SMartin Willi strcpy(p->alg_name, algo->name); 3714447bb33SMartin Willi if (!p->alg_trunc_len) 3724447bb33SMartin Willi p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; 3734447bb33SMartin Willi 3744447bb33SMartin Willi *algpp = p; 3754447bb33SMartin Willi return 0; 3764447bb33SMartin Willi } 3774447bb33SMartin Willi 37869b0137fSHerbert Xu static int attach_aead(struct xfrm_state *x, struct nlattr *rta) 3791a6509d9SHerbert Xu { 3801a6509d9SHerbert Xu struct xfrm_algo_aead *p, *ualg; 3811a6509d9SHerbert Xu struct xfrm_algo_desc *algo; 3821a6509d9SHerbert Xu 3831a6509d9SHerbert Xu if (!rta) 3841a6509d9SHerbert Xu return 0; 3851a6509d9SHerbert Xu 3861a6509d9SHerbert Xu ualg = nla_data(rta); 3871a6509d9SHerbert Xu 3881a6509d9SHerbert Xu algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1); 3891a6509d9SHerbert Xu if (!algo) 3901a6509d9SHerbert Xu return -ENOSYS; 39169b0137fSHerbert Xu x->props.ealgo = algo->desc.sadb_alg_id; 3921a6509d9SHerbert Xu 3931a6509d9SHerbert Xu p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL); 3941a6509d9SHerbert Xu if (!p) 3951a6509d9SHerbert Xu return -ENOMEM; 3961a6509d9SHerbert Xu 3971a6509d9SHerbert Xu strcpy(p->alg_name, algo->name); 39869b0137fSHerbert Xu x->aead = p; 39969b0137fSHerbert Xu x->geniv = algo->uinfo.aead.geniv; 4001a6509d9SHerbert Xu return 0; 4011a6509d9SHerbert Xu } 4021a6509d9SHerbert Xu 403e2b19125SSteffen Klassert static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_esn, 404e2b19125SSteffen Klassert struct nlattr *rp) 405e2b19125SSteffen Klassert { 406e2b19125SSteffen Klassert struct xfrm_replay_state_esn *up; 407ecd79187SMathias Krause int ulen; 408e2b19125SSteffen Klassert 409e2b19125SSteffen Klassert if (!replay_esn || !rp) 410e2b19125SSteffen Klassert return 0; 411e2b19125SSteffen Klassert 412e2b19125SSteffen Klassert up = nla_data(rp); 413ecd79187SMathias Krause ulen = xfrm_replay_state_esn_len(up); 414e2b19125SSteffen Klassert 415ecd79187SMathias Krause if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) 416e2b19125SSteffen Klassert return -EINVAL; 417e2b19125SSteffen Klassert 418e2b19125SSteffen Klassert return 0; 419e2b19125SSteffen Klassert } 420e2b19125SSteffen Klassert 421d8647b79SSteffen Klassert static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn, 422d8647b79SSteffen Klassert struct xfrm_replay_state_esn **preplay_esn, 423d8647b79SSteffen Klassert struct nlattr *rta) 424d8647b79SSteffen Klassert { 425d8647b79SSteffen Klassert struct xfrm_replay_state_esn *p, *pp, *up; 426ecd79187SMathias Krause int klen, ulen; 427d8647b79SSteffen Klassert 428d8647b79SSteffen Klassert if (!rta) 429d8647b79SSteffen Klassert return 0; 430d8647b79SSteffen Klassert 431d8647b79SSteffen Klassert up = nla_data(rta); 432ecd79187SMathias Krause klen = xfrm_replay_state_esn_len(up); 433ecd79187SMathias Krause ulen = nla_len(rta) >= klen ? klen : sizeof(*up); 434d8647b79SSteffen Klassert 435ecd79187SMathias Krause p = kzalloc(klen, GFP_KERNEL); 436d8647b79SSteffen Klassert if (!p) 437d8647b79SSteffen Klassert return -ENOMEM; 438d8647b79SSteffen Klassert 439ecd79187SMathias Krause pp = kzalloc(klen, GFP_KERNEL); 440d8647b79SSteffen Klassert if (!pp) { 441d8647b79SSteffen Klassert kfree(p); 442d8647b79SSteffen Klassert return -ENOMEM; 443d8647b79SSteffen Klassert } 444d8647b79SSteffen Klassert 445ecd79187SMathias Krause memcpy(p, up, ulen); 446ecd79187SMathias Krause memcpy(pp, up, ulen); 447ecd79187SMathias Krause 448d8647b79SSteffen Klassert *replay_esn = p; 449d8647b79SSteffen Klassert *preplay_esn = pp; 450d8647b79SSteffen Klassert 451d8647b79SSteffen Klassert return 0; 452d8647b79SSteffen Klassert } 453d8647b79SSteffen Klassert 454661697f7SJoy Latten static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) 455df71837dSTrent Jaeger { 456df71837dSTrent Jaeger int len = 0; 457df71837dSTrent Jaeger 458df71837dSTrent Jaeger if (xfrm_ctx) { 459df71837dSTrent Jaeger len += sizeof(struct xfrm_user_sec_ctx); 460df71837dSTrent Jaeger len += xfrm_ctx->ctx_len; 461df71837dSTrent Jaeger } 462df71837dSTrent Jaeger return len; 463df71837dSTrent Jaeger } 464df71837dSTrent Jaeger 4651da177e4SLinus Torvalds static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 4661da177e4SLinus Torvalds { 4671da177e4SLinus Torvalds memcpy(&x->id, &p->id, sizeof(x->id)); 4681da177e4SLinus Torvalds memcpy(&x->sel, &p->sel, sizeof(x->sel)); 4691da177e4SLinus Torvalds memcpy(&x->lft, &p->lft, sizeof(x->lft)); 4701da177e4SLinus Torvalds x->props.mode = p->mode; 47133fce60dSFan Du x->props.replay_window = min_t(unsigned int, p->replay_window, 47233fce60dSFan Du sizeof(x->replay.bitmap) * 8); 4731da177e4SLinus Torvalds x->props.reqid = p->reqid; 4741da177e4SLinus Torvalds x->props.family = p->family; 47554489c14SDavid S. Miller memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); 4761da177e4SLinus Torvalds x->props.flags = p->flags; 477196b0036SHerbert Xu 478ccf9b3b8SSteffen Klassert if (!x->sel.family && !(p->flags & XFRM_STATE_AF_UNSPEC)) 479196b0036SHerbert Xu x->sel.family = p->family; 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds 482d51d081dSJamal Hadi Salim /* 483d51d081dSJamal Hadi Salim * someday when pfkey also has support, we could have the code 484d51d081dSJamal Hadi Salim * somehow made shareable and move it to xfrm_state.c - JHS 485d51d081dSJamal Hadi Salim * 486d51d081dSJamal Hadi Salim */ 487e3ac104dSMathias Krause static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs, 488e3ac104dSMathias Krause int update_esn) 489d51d081dSJamal Hadi Salim { 4905424f32eSThomas Graf struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; 491e3ac104dSMathias Krause struct nlattr *re = update_esn ? attrs[XFRMA_REPLAY_ESN_VAL] : NULL; 4925424f32eSThomas Graf struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; 4935424f32eSThomas Graf struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; 4945424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; 495d51d081dSJamal Hadi Salim 496d8647b79SSteffen Klassert if (re) { 497d8647b79SSteffen Klassert struct xfrm_replay_state_esn *replay_esn; 498d8647b79SSteffen Klassert replay_esn = nla_data(re); 499d8647b79SSteffen Klassert memcpy(x->replay_esn, replay_esn, 500d8647b79SSteffen Klassert xfrm_replay_state_esn_len(replay_esn)); 501d8647b79SSteffen Klassert memcpy(x->preplay_esn, replay_esn, 502d8647b79SSteffen Klassert xfrm_replay_state_esn_len(replay_esn)); 503d8647b79SSteffen Klassert } 504d8647b79SSteffen Klassert 505d51d081dSJamal Hadi Salim if (rp) { 506d51d081dSJamal Hadi Salim struct xfrm_replay_state *replay; 5075424f32eSThomas Graf replay = nla_data(rp); 508d51d081dSJamal Hadi Salim memcpy(&x->replay, replay, sizeof(*replay)); 509d51d081dSJamal Hadi Salim memcpy(&x->preplay, replay, sizeof(*replay)); 510d51d081dSJamal Hadi Salim } 511d51d081dSJamal Hadi Salim 512d51d081dSJamal Hadi Salim if (lt) { 513d51d081dSJamal Hadi Salim struct xfrm_lifetime_cur *ltime; 5145424f32eSThomas Graf ltime = nla_data(lt); 515d51d081dSJamal Hadi Salim x->curlft.bytes = ltime->bytes; 516d51d081dSJamal Hadi Salim x->curlft.packets = ltime->packets; 517d51d081dSJamal Hadi Salim x->curlft.add_time = ltime->add_time; 518d51d081dSJamal Hadi Salim x->curlft.use_time = ltime->use_time; 519d51d081dSJamal Hadi Salim } 520d51d081dSJamal Hadi Salim 521cf5cb79fSThomas Graf if (et) 5225424f32eSThomas Graf x->replay_maxage = nla_get_u32(et); 523d51d081dSJamal Hadi Salim 524cf5cb79fSThomas Graf if (rt) 5255424f32eSThomas Graf x->replay_maxdiff = nla_get_u32(rt); 526d51d081dSJamal Hadi Salim } 527d51d081dSJamal Hadi Salim 528fc34acd3SAlexey Dobriyan static struct xfrm_state *xfrm_state_construct(struct net *net, 529fc34acd3SAlexey Dobriyan struct xfrm_usersa_info *p, 5305424f32eSThomas Graf struct nlattr **attrs, 5311da177e4SLinus Torvalds int *errp) 5321da177e4SLinus Torvalds { 533fc34acd3SAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(net); 5341da177e4SLinus Torvalds int err = -ENOMEM; 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds if (!x) 5371da177e4SLinus Torvalds goto error_no_put; 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds copy_from_user_state(x, p); 5401da177e4SLinus Torvalds 541a947b0a9SNicolas Dichtel if (attrs[XFRMA_SA_EXTRA_FLAGS]) 542a947b0a9SNicolas Dichtel x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]); 543a947b0a9SNicolas Dichtel 54469b0137fSHerbert Xu if ((err = attach_aead(x, attrs[XFRMA_ALG_AEAD]))) 5451a6509d9SHerbert Xu goto error; 5464447bb33SMartin Willi if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo, 5474447bb33SMartin Willi attrs[XFRMA_ALG_AUTH_TRUNC]))) 5484447bb33SMartin Willi goto error; 5494447bb33SMartin Willi if (!x->props.aalgo) { 5504447bb33SMartin Willi if ((err = attach_auth(&x->aalg, &x->props.aalgo, 55135a7aa08SThomas Graf attrs[XFRMA_ALG_AUTH]))) 5521da177e4SLinus Torvalds goto error; 5534447bb33SMartin Willi } 55469b0137fSHerbert Xu if ((err = attach_crypt(x, attrs[XFRMA_ALG_CRYPT]))) 5551da177e4SLinus Torvalds goto error; 5561da177e4SLinus Torvalds if ((err = attach_one_algo(&x->calg, &x->props.calgo, 5571da177e4SLinus Torvalds xfrm_calg_get_byname, 55835a7aa08SThomas Graf attrs[XFRMA_ALG_COMP]))) 5591da177e4SLinus Torvalds goto error; 560fd21150aSThomas Graf 561fd21150aSThomas Graf if (attrs[XFRMA_ENCAP]) { 562fd21150aSThomas Graf x->encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]), 563fd21150aSThomas Graf sizeof(*x->encap), GFP_KERNEL); 564fd21150aSThomas Graf if (x->encap == NULL) 5651da177e4SLinus Torvalds goto error; 566fd21150aSThomas Graf } 567fd21150aSThomas Graf 56835d2856bSMartin Willi if (attrs[XFRMA_TFCPAD]) 56935d2856bSMartin Willi x->tfcpad = nla_get_u32(attrs[XFRMA_TFCPAD]); 57035d2856bSMartin Willi 571fd21150aSThomas Graf if (attrs[XFRMA_COADDR]) { 572fd21150aSThomas Graf x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]), 573fd21150aSThomas Graf sizeof(*x->coaddr), GFP_KERNEL); 574fd21150aSThomas Graf if (x->coaddr == NULL) 575060f02a3SNoriaki TAKAMIYA goto error; 576fd21150aSThomas Graf } 577fd21150aSThomas Graf 5786f26b61eSJamal Hadi Salim xfrm_mark_get(attrs, &x->mark); 5796f26b61eSJamal Hadi Salim 580a454f0ccSWei Yongjun err = __xfrm_init_state(x, false); 5811da177e4SLinus Torvalds if (err) 5821da177e4SLinus Torvalds goto error; 5831da177e4SLinus Torvalds 5842f30ea50SMathias Krause if (attrs[XFRMA_SEC_CTX]) { 5852f30ea50SMathias Krause err = security_xfrm_state_alloc(x, 5862f30ea50SMathias Krause nla_data(attrs[XFRMA_SEC_CTX])); 5872f30ea50SMathias Krause if (err) 588df71837dSTrent Jaeger goto error; 5892f30ea50SMathias Krause } 590df71837dSTrent Jaeger 591d8647b79SSteffen Klassert if ((err = xfrm_alloc_replay_state_esn(&x->replay_esn, &x->preplay_esn, 592d8647b79SSteffen Klassert attrs[XFRMA_REPLAY_ESN_VAL]))) 593d8647b79SSteffen Klassert goto error; 594d8647b79SSteffen Klassert 5951da177e4SLinus Torvalds x->km.seq = p->seq; 596b27aeadbSAlexey Dobriyan x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth; 597d51d081dSJamal Hadi Salim /* sysctl_xfrm_aevent_etime is in 100ms units */ 598b27aeadbSAlexey Dobriyan x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M; 599d51d081dSJamal Hadi Salim 6009fdc4883SSteffen Klassert if ((err = xfrm_init_replay(x))) 6019fdc4883SSteffen Klassert goto error; 602d51d081dSJamal Hadi Salim 6039fdc4883SSteffen Klassert /* override default values from above */ 604e3ac104dSMathias Krause xfrm_update_ae_params(x, attrs, 0); 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds return x; 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds error: 6091da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 6101da177e4SLinus Torvalds xfrm_state_put(x); 6111da177e4SLinus Torvalds error_no_put: 6121da177e4SLinus Torvalds *errp = err; 6131da177e4SLinus Torvalds return NULL; 6141da177e4SLinus Torvalds } 6151da177e4SLinus Torvalds 61622e70050SChristoph Hellwig static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 6175424f32eSThomas Graf struct nlattr **attrs) 6181da177e4SLinus Torvalds { 619fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 6207b67c857SThomas Graf struct xfrm_usersa_info *p = nlmsg_data(nlh); 6211da177e4SLinus Torvalds struct xfrm_state *x; 6221da177e4SLinus Torvalds int err; 62326b15dadSJamal Hadi Salim struct km_event c; 6241da177e4SLinus Torvalds 62535a7aa08SThomas Graf err = verify_newsa_info(p, attrs); 6261da177e4SLinus Torvalds if (err) 6271da177e4SLinus Torvalds return err; 6281da177e4SLinus Torvalds 629fc34acd3SAlexey Dobriyan x = xfrm_state_construct(net, p, attrs, &err); 6301da177e4SLinus Torvalds if (!x) 6311da177e4SLinus Torvalds return err; 6321da177e4SLinus Torvalds 63326b15dadSJamal Hadi Salim xfrm_state_hold(x); 6341da177e4SLinus Torvalds if (nlh->nlmsg_type == XFRM_MSG_NEWSA) 6351da177e4SLinus Torvalds err = xfrm_state_add(x); 6361da177e4SLinus Torvalds else 6371da177e4SLinus Torvalds err = xfrm_state_update(x); 6381da177e4SLinus Torvalds 6392e71029eSTetsuo Handa xfrm_audit_state_add(x, err ? 0 : 1, true); 640161a09e7SJoy Latten 6411da177e4SLinus Torvalds if (err < 0) { 6421da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 64321380b81SHerbert Xu __xfrm_state_put(x); 6447d6dfe1fSPatrick McHardy goto out; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 64726b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 64815e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 649f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 65026b15dadSJamal Hadi Salim 65126b15dadSJamal Hadi Salim km_state_notify(x, &c); 6527d6dfe1fSPatrick McHardy out: 65326b15dadSJamal Hadi Salim xfrm_state_put(x); 6541da177e4SLinus Torvalds return err; 6551da177e4SLinus Torvalds } 6561da177e4SLinus Torvalds 657fc34acd3SAlexey Dobriyan static struct xfrm_state *xfrm_user_state_lookup(struct net *net, 658fc34acd3SAlexey Dobriyan struct xfrm_usersa_id *p, 6595424f32eSThomas Graf struct nlattr **attrs, 660eb2971b6SMasahide NAKAMURA int *errp) 661eb2971b6SMasahide NAKAMURA { 662eb2971b6SMasahide NAKAMURA struct xfrm_state *x = NULL; 6636f26b61eSJamal Hadi Salim struct xfrm_mark m; 664eb2971b6SMasahide NAKAMURA int err; 6656f26b61eSJamal Hadi Salim u32 mark = xfrm_mark_get(attrs, &m); 666eb2971b6SMasahide NAKAMURA 667eb2971b6SMasahide NAKAMURA if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { 668eb2971b6SMasahide NAKAMURA err = -ESRCH; 6696f26b61eSJamal Hadi Salim x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family); 670eb2971b6SMasahide NAKAMURA } else { 671eb2971b6SMasahide NAKAMURA xfrm_address_t *saddr = NULL; 672eb2971b6SMasahide NAKAMURA 67335a7aa08SThomas Graf verify_one_addr(attrs, XFRMA_SRCADDR, &saddr); 674eb2971b6SMasahide NAKAMURA if (!saddr) { 675eb2971b6SMasahide NAKAMURA err = -EINVAL; 676eb2971b6SMasahide NAKAMURA goto out; 677eb2971b6SMasahide NAKAMURA } 678eb2971b6SMasahide NAKAMURA 6799abbffeeSMasahide NAKAMURA err = -ESRCH; 6806f26b61eSJamal Hadi Salim x = xfrm_state_lookup_byaddr(net, mark, 6816f26b61eSJamal Hadi Salim &p->daddr, saddr, 682221df1edSAlexey Dobriyan p->proto, p->family); 683eb2971b6SMasahide NAKAMURA } 684eb2971b6SMasahide NAKAMURA 685eb2971b6SMasahide NAKAMURA out: 686eb2971b6SMasahide NAKAMURA if (!x && errp) 687eb2971b6SMasahide NAKAMURA *errp = err; 688eb2971b6SMasahide NAKAMURA return x; 689eb2971b6SMasahide NAKAMURA } 690eb2971b6SMasahide NAKAMURA 69122e70050SChristoph Hellwig static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 6925424f32eSThomas Graf struct nlattr **attrs) 6931da177e4SLinus Torvalds { 694fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 6951da177e4SLinus Torvalds struct xfrm_state *x; 696eb2971b6SMasahide NAKAMURA int err = -ESRCH; 69726b15dadSJamal Hadi Salim struct km_event c; 6987b67c857SThomas Graf struct xfrm_usersa_id *p = nlmsg_data(nlh); 6991da177e4SLinus Torvalds 700fc34acd3SAlexey Dobriyan x = xfrm_user_state_lookup(net, p, attrs, &err); 7011da177e4SLinus Torvalds if (x == NULL) 702eb2971b6SMasahide NAKAMURA return err; 7031da177e4SLinus Torvalds 7046f68dc37SDavid S. Miller if ((err = security_xfrm_state_delete(x)) != 0) 705c8c05a8eSCatherine Zhang goto out; 706c8c05a8eSCatherine Zhang 7071da177e4SLinus Torvalds if (xfrm_state_kern(x)) { 708c8c05a8eSCatherine Zhang err = -EPERM; 709c8c05a8eSCatherine Zhang goto out; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 71226b15dadSJamal Hadi Salim err = xfrm_state_delete(x); 713161a09e7SJoy Latten 714c8c05a8eSCatherine Zhang if (err < 0) 715c8c05a8eSCatherine Zhang goto out; 71626b15dadSJamal Hadi Salim 71726b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 71815e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 719f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 72026b15dadSJamal Hadi Salim km_state_notify(x, &c); 7211da177e4SLinus Torvalds 722c8c05a8eSCatherine Zhang out: 7232e71029eSTetsuo Handa xfrm_audit_state_delete(x, err ? 0 : 1, true); 724c8c05a8eSCatherine Zhang xfrm_state_put(x); 72526b15dadSJamal Hadi Salim return err; 7261da177e4SLinus Torvalds } 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 7291da177e4SLinus Torvalds { 730f778a636SMathias Krause memset(p, 0, sizeof(*p)); 7311da177e4SLinus Torvalds memcpy(&p->id, &x->id, sizeof(p->id)); 7321da177e4SLinus Torvalds memcpy(&p->sel, &x->sel, sizeof(p->sel)); 7331da177e4SLinus Torvalds memcpy(&p->lft, &x->lft, sizeof(p->lft)); 7341da177e4SLinus Torvalds memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); 735e33d4f13SSowmini Varadhan put_unaligned(x->stats.replay_window, &p->stats.replay_window); 736e33d4f13SSowmini Varadhan put_unaligned(x->stats.replay, &p->stats.replay); 737e33d4f13SSowmini Varadhan put_unaligned(x->stats.integrity_failed, &p->stats.integrity_failed); 73854489c14SDavid S. Miller memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr)); 7391da177e4SLinus Torvalds p->mode = x->props.mode; 7401da177e4SLinus Torvalds p->replay_window = x->props.replay_window; 7411da177e4SLinus Torvalds p->reqid = x->props.reqid; 7421da177e4SLinus Torvalds p->family = x->props.family; 7431da177e4SLinus Torvalds p->flags = x->props.flags; 7441da177e4SLinus Torvalds p->seq = x->km.seq; 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds struct xfrm_dump_info { 7481da177e4SLinus Torvalds struct sk_buff *in_skb; 7491da177e4SLinus Torvalds struct sk_buff *out_skb; 7501da177e4SLinus Torvalds u32 nlmsg_seq; 7511da177e4SLinus Torvalds u16 nlmsg_flags; 7521da177e4SLinus Torvalds }; 7531da177e4SLinus Torvalds 754c0144beaSThomas Graf static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) 755c0144beaSThomas Graf { 756c0144beaSThomas Graf struct xfrm_user_sec_ctx *uctx; 757c0144beaSThomas Graf struct nlattr *attr; 75868325d3bSHerbert Xu int ctx_size = sizeof(*uctx) + s->ctx_len; 759c0144beaSThomas Graf 760c0144beaSThomas Graf attr = nla_reserve(skb, XFRMA_SEC_CTX, ctx_size); 761c0144beaSThomas Graf if (attr == NULL) 762c0144beaSThomas Graf return -EMSGSIZE; 763c0144beaSThomas Graf 764c0144beaSThomas Graf uctx = nla_data(attr); 765c0144beaSThomas Graf uctx->exttype = XFRMA_SEC_CTX; 766c0144beaSThomas Graf uctx->len = ctx_size; 767c0144beaSThomas Graf uctx->ctx_doi = s->ctx_doi; 768c0144beaSThomas Graf uctx->ctx_alg = s->ctx_alg; 769c0144beaSThomas Graf uctx->ctx_len = s->ctx_len; 770c0144beaSThomas Graf memcpy(uctx + 1, s->ctx_str, s->ctx_len); 771c0144beaSThomas Graf 772c0144beaSThomas Graf return 0; 773c0144beaSThomas Graf } 774c0144beaSThomas Graf 7754447bb33SMartin Willi static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb) 7764447bb33SMartin Willi { 7774447bb33SMartin Willi struct xfrm_algo *algo; 7784447bb33SMartin Willi struct nlattr *nla; 7794447bb33SMartin Willi 7804447bb33SMartin Willi nla = nla_reserve(skb, XFRMA_ALG_AUTH, 7814447bb33SMartin Willi sizeof(*algo) + (auth->alg_key_len + 7) / 8); 7824447bb33SMartin Willi if (!nla) 7834447bb33SMartin Willi return -EMSGSIZE; 7844447bb33SMartin Willi 7854447bb33SMartin Willi algo = nla_data(nla); 7864c87308bSMathias Krause strncpy(algo->alg_name, auth->alg_name, sizeof(algo->alg_name)); 7874447bb33SMartin Willi memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8); 7884447bb33SMartin Willi algo->alg_key_len = auth->alg_key_len; 7894447bb33SMartin Willi 7904447bb33SMartin Willi return 0; 7914447bb33SMartin Willi } 7924447bb33SMartin Willi 79368325d3bSHerbert Xu /* Don't change this without updating xfrm_sa_len! */ 79468325d3bSHerbert Xu static int copy_to_user_state_extra(struct xfrm_state *x, 79568325d3bSHerbert Xu struct xfrm_usersa_info *p, 79668325d3bSHerbert Xu struct sk_buff *skb) 7971da177e4SLinus Torvalds { 7981d1e34ddSDavid S. Miller int ret = 0; 7991d1e34ddSDavid S. Miller 8001da177e4SLinus Torvalds copy_to_user_state(x, p); 8011da177e4SLinus Torvalds 802a947b0a9SNicolas Dichtel if (x->props.extra_flags) { 803a947b0a9SNicolas Dichtel ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS, 804a947b0a9SNicolas Dichtel x->props.extra_flags); 805a947b0a9SNicolas Dichtel if (ret) 806a947b0a9SNicolas Dichtel goto out; 807a947b0a9SNicolas Dichtel } 808a947b0a9SNicolas Dichtel 8091d1e34ddSDavid S. Miller if (x->coaddr) { 8101d1e34ddSDavid S. Miller ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); 8111d1e34ddSDavid S. Miller if (ret) 8121d1e34ddSDavid S. Miller goto out; 8131d1e34ddSDavid S. Miller } 8141d1e34ddSDavid S. Miller if (x->lastused) { 815de95c4a4SNicolas Dichtel ret = nla_put_u64_64bit(skb, XFRMA_LASTUSED, x->lastused, 816de95c4a4SNicolas Dichtel XFRMA_PAD); 8171d1e34ddSDavid S. Miller if (ret) 8181d1e34ddSDavid S. Miller goto out; 8191d1e34ddSDavid S. Miller } 8201d1e34ddSDavid S. Miller if (x->aead) { 8211d1e34ddSDavid S. Miller ret = nla_put(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); 8221d1e34ddSDavid S. Miller if (ret) 8231d1e34ddSDavid S. Miller goto out; 8241d1e34ddSDavid S. Miller } 8251d1e34ddSDavid S. Miller if (x->aalg) { 8261d1e34ddSDavid S. Miller ret = copy_to_user_auth(x->aalg, skb); 8271d1e34ddSDavid S. Miller if (!ret) 8281d1e34ddSDavid S. Miller ret = nla_put(skb, XFRMA_ALG_AUTH_TRUNC, 8291d1e34ddSDavid S. Miller xfrm_alg_auth_len(x->aalg), x->aalg); 8301d1e34ddSDavid S. Miller if (ret) 8311d1e34ddSDavid S. Miller goto out; 8321d1e34ddSDavid S. Miller } 8331d1e34ddSDavid S. Miller if (x->ealg) { 8341d1e34ddSDavid S. Miller ret = nla_put(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); 8351d1e34ddSDavid S. Miller if (ret) 8361d1e34ddSDavid S. Miller goto out; 8371d1e34ddSDavid S. Miller } 8381d1e34ddSDavid S. Miller if (x->calg) { 8391d1e34ddSDavid S. Miller ret = nla_put(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); 8401d1e34ddSDavid S. Miller if (ret) 8411d1e34ddSDavid S. Miller goto out; 8421d1e34ddSDavid S. Miller } 8431d1e34ddSDavid S. Miller if (x->encap) { 8441d1e34ddSDavid S. Miller ret = nla_put(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); 8451d1e34ddSDavid S. Miller if (ret) 8461d1e34ddSDavid S. Miller goto out; 8471d1e34ddSDavid S. Miller } 8481d1e34ddSDavid S. Miller if (x->tfcpad) { 8491d1e34ddSDavid S. Miller ret = nla_put_u32(skb, XFRMA_TFCPAD, x->tfcpad); 8501d1e34ddSDavid S. Miller if (ret) 8511d1e34ddSDavid S. Miller goto out; 8521d1e34ddSDavid S. Miller } 8531d1e34ddSDavid S. Miller ret = xfrm_mark_put(skb, &x->mark); 8541d1e34ddSDavid S. Miller if (ret) 8551d1e34ddSDavid S. Miller goto out; 856f293a5e3Sdingzhi if (x->replay_esn) 8571d1e34ddSDavid S. Miller ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL, 858d0fde795SDavid S. Miller xfrm_replay_state_esn_len(x->replay_esn), 8591d1e34ddSDavid S. Miller x->replay_esn); 860f293a5e3Sdingzhi else 861f293a5e3Sdingzhi ret = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), 862f293a5e3Sdingzhi &x->replay); 8631d1e34ddSDavid S. Miller if (ret) 8641d1e34ddSDavid S. Miller goto out; 8651d1e34ddSDavid S. Miller if (x->security) 8661d1e34ddSDavid S. Miller ret = copy_sec_ctx(x->security, skb); 8671d1e34ddSDavid S. Miller out: 8681d1e34ddSDavid S. Miller return ret; 86968325d3bSHerbert Xu } 87068325d3bSHerbert Xu 87168325d3bSHerbert Xu static int dump_one_state(struct xfrm_state *x, int count, void *ptr) 87268325d3bSHerbert Xu { 87368325d3bSHerbert Xu struct xfrm_dump_info *sp = ptr; 87468325d3bSHerbert Xu struct sk_buff *in_skb = sp->in_skb; 87568325d3bSHerbert Xu struct sk_buff *skb = sp->out_skb; 87668325d3bSHerbert Xu struct xfrm_usersa_info *p; 87768325d3bSHerbert Xu struct nlmsghdr *nlh; 87868325d3bSHerbert Xu int err; 87968325d3bSHerbert Xu 88015e47304SEric W. Biederman nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq, 88168325d3bSHerbert Xu XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); 88268325d3bSHerbert Xu if (nlh == NULL) 88368325d3bSHerbert Xu return -EMSGSIZE; 88468325d3bSHerbert Xu 88568325d3bSHerbert Xu p = nlmsg_data(nlh); 88668325d3bSHerbert Xu 88768325d3bSHerbert Xu err = copy_to_user_state_extra(x, p, skb); 8881d1e34ddSDavid S. Miller if (err) { 8899825069dSThomas Graf nlmsg_cancel(skb, nlh); 89068325d3bSHerbert Xu return err; 8911da177e4SLinus Torvalds } 8921d1e34ddSDavid S. Miller nlmsg_end(skb, nlh); 8931d1e34ddSDavid S. Miller return 0; 8941d1e34ddSDavid S. Miller } 8951da177e4SLinus Torvalds 8964c563f76STimo Teras static int xfrm_dump_sa_done(struct netlink_callback *cb) 8974c563f76STimo Teras { 8984c563f76STimo Teras struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; 899283bc9f3SFan Du struct sock *sk = cb->skb->sk; 900283bc9f3SFan Du struct net *net = sock_net(sk); 901283bc9f3SFan Du 9021ba5bf99SVegard Nossum if (cb->args[0]) 903283bc9f3SFan Du xfrm_state_walk_done(walk, net); 9044c563f76STimo Teras return 0; 9054c563f76STimo Teras } 9064c563f76STimo Teras 907d3623099SNicolas Dichtel static const struct nla_policy xfrma_policy[XFRMA_MAX+1]; 9081da177e4SLinus Torvalds static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) 9091da177e4SLinus Torvalds { 910fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 9114c563f76STimo Teras struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; 9121da177e4SLinus Torvalds struct xfrm_dump_info info; 9131da177e4SLinus Torvalds 9144c563f76STimo Teras BUILD_BUG_ON(sizeof(struct xfrm_state_walk) > 9154c563f76STimo Teras sizeof(cb->args) - sizeof(cb->args[0])); 9164c563f76STimo Teras 9171da177e4SLinus Torvalds info.in_skb = cb->skb; 9181da177e4SLinus Torvalds info.out_skb = skb; 9191da177e4SLinus Torvalds info.nlmsg_seq = cb->nlh->nlmsg_seq; 9201da177e4SLinus Torvalds info.nlmsg_flags = NLM_F_MULTI; 9214c563f76STimo Teras 9224c563f76STimo Teras if (!cb->args[0]) { 923d3623099SNicolas Dichtel struct nlattr *attrs[XFRMA_MAX+1]; 924870a2df4SNicolas Dichtel struct xfrm_address_filter *filter = NULL; 925d3623099SNicolas Dichtel u8 proto = 0; 926d3623099SNicolas Dichtel int err; 927d3623099SNicolas Dichtel 928d3623099SNicolas Dichtel err = nlmsg_parse(cb->nlh, 0, attrs, XFRMA_MAX, 929d3623099SNicolas Dichtel xfrma_policy); 930d3623099SNicolas Dichtel if (err < 0) 931d3623099SNicolas Dichtel return err; 932d3623099SNicolas Dichtel 933870a2df4SNicolas Dichtel if (attrs[XFRMA_ADDRESS_FILTER]) { 934df367561SAndrzej Hajda filter = kmemdup(nla_data(attrs[XFRMA_ADDRESS_FILTER]), 935df367561SAndrzej Hajda sizeof(*filter), GFP_KERNEL); 936d3623099SNicolas Dichtel if (filter == NULL) 937d3623099SNicolas Dichtel return -ENOMEM; 938d3623099SNicolas Dichtel } 939d3623099SNicolas Dichtel 940d3623099SNicolas Dichtel if (attrs[XFRMA_PROTO]) 941d3623099SNicolas Dichtel proto = nla_get_u8(attrs[XFRMA_PROTO]); 942d3623099SNicolas Dichtel 943d3623099SNicolas Dichtel xfrm_state_walk_init(walk, proto, filter); 9441ba5bf99SVegard Nossum cb->args[0] = 1; 9454c563f76STimo Teras } 9464c563f76STimo Teras 947fc34acd3SAlexey Dobriyan (void) xfrm_state_walk(net, walk, dump_one_state, &info); 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds return skb->len; 9501da177e4SLinus Torvalds } 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, 9531da177e4SLinus Torvalds struct xfrm_state *x, u32 seq) 9541da177e4SLinus Torvalds { 9551da177e4SLinus Torvalds struct xfrm_dump_info info; 9561da177e4SLinus Torvalds struct sk_buff *skb; 957864745d2SMathias Krause int err; 9581da177e4SLinus Torvalds 9597deb2264SThomas Graf skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 9601da177e4SLinus Torvalds if (!skb) 9611da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds info.in_skb = in_skb; 9641da177e4SLinus Torvalds info.out_skb = skb; 9651da177e4SLinus Torvalds info.nlmsg_seq = seq; 9661da177e4SLinus Torvalds info.nlmsg_flags = 0; 9671da177e4SLinus Torvalds 968864745d2SMathias Krause err = dump_one_state(x, 0, &info); 969864745d2SMathias Krause if (err) { 9701da177e4SLinus Torvalds kfree_skb(skb); 971864745d2SMathias Krause return ERR_PTR(err); 9721da177e4SLinus Torvalds } 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds return skb; 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds 97721ee543eSMichal Kubecek /* A wrapper for nlmsg_multicast() checking that nlsk is still available. 97821ee543eSMichal Kubecek * Must be called with RCU read lock. 97921ee543eSMichal Kubecek */ 98021ee543eSMichal Kubecek static inline int xfrm_nlmsg_multicast(struct net *net, struct sk_buff *skb, 98121ee543eSMichal Kubecek u32 pid, unsigned int group) 98221ee543eSMichal Kubecek { 98321ee543eSMichal Kubecek struct sock *nlsk = rcu_dereference(net->xfrm.nlsk); 98421ee543eSMichal Kubecek 98521ee543eSMichal Kubecek if (nlsk) 98621ee543eSMichal Kubecek return nlmsg_multicast(nlsk, skb, pid, group, GFP_ATOMIC); 98721ee543eSMichal Kubecek else 98821ee543eSMichal Kubecek return -1; 98921ee543eSMichal Kubecek } 99021ee543eSMichal Kubecek 9917deb2264SThomas Graf static inline size_t xfrm_spdinfo_msgsize(void) 9927deb2264SThomas Graf { 9937deb2264SThomas Graf return NLMSG_ALIGN(4) 9947deb2264SThomas Graf + nla_total_size(sizeof(struct xfrmu_spdinfo)) 995880a6fabSChristophe Gouault + nla_total_size(sizeof(struct xfrmu_spdhinfo)) 996880a6fabSChristophe Gouault + nla_total_size(sizeof(struct xfrmu_spdhthresh)) 997880a6fabSChristophe Gouault + nla_total_size(sizeof(struct xfrmu_spdhthresh)); 9987deb2264SThomas Graf } 9997deb2264SThomas Graf 1000e071041bSAlexey Dobriyan static int build_spdinfo(struct sk_buff *skb, struct net *net, 100115e47304SEric W. Biederman u32 portid, u32 seq, u32 flags) 1002ecfd6b18SJamal Hadi Salim { 10035a6d3416SJamal Hadi Salim struct xfrmk_spdinfo si; 10045a6d3416SJamal Hadi Salim struct xfrmu_spdinfo spc; 10055a6d3416SJamal Hadi Salim struct xfrmu_spdhinfo sph; 1006880a6fabSChristophe Gouault struct xfrmu_spdhthresh spt4, spt6; 1007ecfd6b18SJamal Hadi Salim struct nlmsghdr *nlh; 10081d1e34ddSDavid S. Miller int err; 1009ecfd6b18SJamal Hadi Salim u32 *f; 1010880a6fabSChristophe Gouault unsigned lseq; 1011ecfd6b18SJamal Hadi Salim 101215e47304SEric W. Biederman nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0); 101325985edcSLucas De Marchi if (nlh == NULL) /* shouldn't really happen ... */ 1014ecfd6b18SJamal Hadi Salim return -EMSGSIZE; 1015ecfd6b18SJamal Hadi Salim 1016ecfd6b18SJamal Hadi Salim f = nlmsg_data(nlh); 1017ecfd6b18SJamal Hadi Salim *f = flags; 1018e071041bSAlexey Dobriyan xfrm_spd_getinfo(net, &si); 10195a6d3416SJamal Hadi Salim spc.incnt = si.incnt; 10205a6d3416SJamal Hadi Salim spc.outcnt = si.outcnt; 10215a6d3416SJamal Hadi Salim spc.fwdcnt = si.fwdcnt; 10225a6d3416SJamal Hadi Salim spc.inscnt = si.inscnt; 10235a6d3416SJamal Hadi Salim spc.outscnt = si.outscnt; 10245a6d3416SJamal Hadi Salim spc.fwdscnt = si.fwdscnt; 10255a6d3416SJamal Hadi Salim sph.spdhcnt = si.spdhcnt; 10265a6d3416SJamal Hadi Salim sph.spdhmcnt = si.spdhmcnt; 1027ecfd6b18SJamal Hadi Salim 1028880a6fabSChristophe Gouault do { 1029880a6fabSChristophe Gouault lseq = read_seqbegin(&net->xfrm.policy_hthresh.lock); 1030880a6fabSChristophe Gouault 1031880a6fabSChristophe Gouault spt4.lbits = net->xfrm.policy_hthresh.lbits4; 1032880a6fabSChristophe Gouault spt4.rbits = net->xfrm.policy_hthresh.rbits4; 1033880a6fabSChristophe Gouault spt6.lbits = net->xfrm.policy_hthresh.lbits6; 1034880a6fabSChristophe Gouault spt6.rbits = net->xfrm.policy_hthresh.rbits6; 1035880a6fabSChristophe Gouault } while (read_seqretry(&net->xfrm.policy_hthresh.lock, lseq)); 1036880a6fabSChristophe Gouault 10371d1e34ddSDavid S. Miller err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc); 10381d1e34ddSDavid S. Miller if (!err) 10391d1e34ddSDavid S. Miller err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph); 1040880a6fabSChristophe Gouault if (!err) 1041880a6fabSChristophe Gouault err = nla_put(skb, XFRMA_SPD_IPV4_HTHRESH, sizeof(spt4), &spt4); 1042880a6fabSChristophe Gouault if (!err) 1043880a6fabSChristophe Gouault err = nla_put(skb, XFRMA_SPD_IPV6_HTHRESH, sizeof(spt6), &spt6); 10441d1e34ddSDavid S. Miller if (err) { 10451d1e34ddSDavid S. Miller nlmsg_cancel(skb, nlh); 10461d1e34ddSDavid S. Miller return err; 10471d1e34ddSDavid S. Miller } 1048ecfd6b18SJamal Hadi Salim 1049053c095aSJohannes Berg nlmsg_end(skb, nlh); 1050053c095aSJohannes Berg return 0; 1051ecfd6b18SJamal Hadi Salim } 1052ecfd6b18SJamal Hadi Salim 1053880a6fabSChristophe Gouault static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, 1054880a6fabSChristophe Gouault struct nlattr **attrs) 1055880a6fabSChristophe Gouault { 1056880a6fabSChristophe Gouault struct net *net = sock_net(skb->sk); 1057880a6fabSChristophe Gouault struct xfrmu_spdhthresh *thresh4 = NULL; 1058880a6fabSChristophe Gouault struct xfrmu_spdhthresh *thresh6 = NULL; 1059880a6fabSChristophe Gouault 1060880a6fabSChristophe Gouault /* selector prefixlen thresholds to hash policies */ 1061880a6fabSChristophe Gouault if (attrs[XFRMA_SPD_IPV4_HTHRESH]) { 1062880a6fabSChristophe Gouault struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH]; 1063880a6fabSChristophe Gouault 1064880a6fabSChristophe Gouault if (nla_len(rta) < sizeof(*thresh4)) 1065880a6fabSChristophe Gouault return -EINVAL; 1066880a6fabSChristophe Gouault thresh4 = nla_data(rta); 1067880a6fabSChristophe Gouault if (thresh4->lbits > 32 || thresh4->rbits > 32) 1068880a6fabSChristophe Gouault return -EINVAL; 1069880a6fabSChristophe Gouault } 1070880a6fabSChristophe Gouault if (attrs[XFRMA_SPD_IPV6_HTHRESH]) { 1071880a6fabSChristophe Gouault struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH]; 1072880a6fabSChristophe Gouault 1073880a6fabSChristophe Gouault if (nla_len(rta) < sizeof(*thresh6)) 1074880a6fabSChristophe Gouault return -EINVAL; 1075880a6fabSChristophe Gouault thresh6 = nla_data(rta); 1076880a6fabSChristophe Gouault if (thresh6->lbits > 128 || thresh6->rbits > 128) 1077880a6fabSChristophe Gouault return -EINVAL; 1078880a6fabSChristophe Gouault } 1079880a6fabSChristophe Gouault 1080880a6fabSChristophe Gouault if (thresh4 || thresh6) { 1081880a6fabSChristophe Gouault write_seqlock(&net->xfrm.policy_hthresh.lock); 1082880a6fabSChristophe Gouault if (thresh4) { 1083880a6fabSChristophe Gouault net->xfrm.policy_hthresh.lbits4 = thresh4->lbits; 1084880a6fabSChristophe Gouault net->xfrm.policy_hthresh.rbits4 = thresh4->rbits; 1085880a6fabSChristophe Gouault } 1086880a6fabSChristophe Gouault if (thresh6) { 1087880a6fabSChristophe Gouault net->xfrm.policy_hthresh.lbits6 = thresh6->lbits; 1088880a6fabSChristophe Gouault net->xfrm.policy_hthresh.rbits6 = thresh6->rbits; 1089880a6fabSChristophe Gouault } 1090880a6fabSChristophe Gouault write_sequnlock(&net->xfrm.policy_hthresh.lock); 1091880a6fabSChristophe Gouault 1092880a6fabSChristophe Gouault xfrm_policy_hash_rebuild(net); 1093880a6fabSChristophe Gouault } 1094880a6fabSChristophe Gouault 1095880a6fabSChristophe Gouault return 0; 1096880a6fabSChristophe Gouault } 1097880a6fabSChristophe Gouault 1098ecfd6b18SJamal Hadi Salim static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, 10995424f32eSThomas Graf struct nlattr **attrs) 1100ecfd6b18SJamal Hadi Salim { 1101a6483b79SAlexey Dobriyan struct net *net = sock_net(skb->sk); 1102ecfd6b18SJamal Hadi Salim struct sk_buff *r_skb; 11037b67c857SThomas Graf u32 *flags = nlmsg_data(nlh); 110415e47304SEric W. Biederman u32 sportid = NETLINK_CB(skb).portid; 1105ecfd6b18SJamal Hadi Salim u32 seq = nlh->nlmsg_seq; 1106ecfd6b18SJamal Hadi Salim 11077deb2264SThomas Graf r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC); 1108ecfd6b18SJamal Hadi Salim if (r_skb == NULL) 1109ecfd6b18SJamal Hadi Salim return -ENOMEM; 1110ecfd6b18SJamal Hadi Salim 111115e47304SEric W. Biederman if (build_spdinfo(r_skb, net, sportid, seq, *flags) < 0) 1112ecfd6b18SJamal Hadi Salim BUG(); 1113ecfd6b18SJamal Hadi Salim 111415e47304SEric W. Biederman return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid); 1115ecfd6b18SJamal Hadi Salim } 1116ecfd6b18SJamal Hadi Salim 11177deb2264SThomas Graf static inline size_t xfrm_sadinfo_msgsize(void) 11187deb2264SThomas Graf { 11197deb2264SThomas Graf return NLMSG_ALIGN(4) 11207deb2264SThomas Graf + nla_total_size(sizeof(struct xfrmu_sadhinfo)) 11217deb2264SThomas Graf + nla_total_size(4); /* XFRMA_SAD_CNT */ 11227deb2264SThomas Graf } 11237deb2264SThomas Graf 1124e071041bSAlexey Dobriyan static int build_sadinfo(struct sk_buff *skb, struct net *net, 112515e47304SEric W. Biederman u32 portid, u32 seq, u32 flags) 112628d8909bSJamal Hadi Salim { 1127af11e316SJamal Hadi Salim struct xfrmk_sadinfo si; 1128af11e316SJamal Hadi Salim struct xfrmu_sadhinfo sh; 112928d8909bSJamal Hadi Salim struct nlmsghdr *nlh; 11301d1e34ddSDavid S. Miller int err; 113128d8909bSJamal Hadi Salim u32 *f; 113228d8909bSJamal Hadi Salim 113315e47304SEric W. Biederman nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0); 113425985edcSLucas De Marchi if (nlh == NULL) /* shouldn't really happen ... */ 113528d8909bSJamal Hadi Salim return -EMSGSIZE; 113628d8909bSJamal Hadi Salim 113728d8909bSJamal Hadi Salim f = nlmsg_data(nlh); 113828d8909bSJamal Hadi Salim *f = flags; 1139e071041bSAlexey Dobriyan xfrm_sad_getinfo(net, &si); 114028d8909bSJamal Hadi Salim 1141af11e316SJamal Hadi Salim sh.sadhmcnt = si.sadhmcnt; 1142af11e316SJamal Hadi Salim sh.sadhcnt = si.sadhcnt; 1143af11e316SJamal Hadi Salim 11441d1e34ddSDavid S. Miller err = nla_put_u32(skb, XFRMA_SAD_CNT, si.sadcnt); 11451d1e34ddSDavid S. Miller if (!err) 11461d1e34ddSDavid S. Miller err = nla_put(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh); 11471d1e34ddSDavid S. Miller if (err) { 11481d1e34ddSDavid S. Miller nlmsg_cancel(skb, nlh); 11491d1e34ddSDavid S. Miller return err; 11501d1e34ddSDavid S. Miller } 115128d8909bSJamal Hadi Salim 1152053c095aSJohannes Berg nlmsg_end(skb, nlh); 1153053c095aSJohannes Berg return 0; 115428d8909bSJamal Hadi Salim } 115528d8909bSJamal Hadi Salim 115628d8909bSJamal Hadi Salim static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, 11575424f32eSThomas Graf struct nlattr **attrs) 115828d8909bSJamal Hadi Salim { 1159a6483b79SAlexey Dobriyan struct net *net = sock_net(skb->sk); 116028d8909bSJamal Hadi Salim struct sk_buff *r_skb; 11617b67c857SThomas Graf u32 *flags = nlmsg_data(nlh); 116215e47304SEric W. Biederman u32 sportid = NETLINK_CB(skb).portid; 116328d8909bSJamal Hadi Salim u32 seq = nlh->nlmsg_seq; 116428d8909bSJamal Hadi Salim 11657deb2264SThomas Graf r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC); 116628d8909bSJamal Hadi Salim if (r_skb == NULL) 116728d8909bSJamal Hadi Salim return -ENOMEM; 116828d8909bSJamal Hadi Salim 116915e47304SEric W. Biederman if (build_sadinfo(r_skb, net, sportid, seq, *flags) < 0) 117028d8909bSJamal Hadi Salim BUG(); 117128d8909bSJamal Hadi Salim 117215e47304SEric W. Biederman return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid); 117328d8909bSJamal Hadi Salim } 117428d8909bSJamal Hadi Salim 117522e70050SChristoph Hellwig static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 11765424f32eSThomas Graf struct nlattr **attrs) 11771da177e4SLinus Torvalds { 1178fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 11797b67c857SThomas Graf struct xfrm_usersa_id *p = nlmsg_data(nlh); 11801da177e4SLinus Torvalds struct xfrm_state *x; 11811da177e4SLinus Torvalds struct sk_buff *resp_skb; 1182eb2971b6SMasahide NAKAMURA int err = -ESRCH; 11831da177e4SLinus Torvalds 1184fc34acd3SAlexey Dobriyan x = xfrm_user_state_lookup(net, p, attrs, &err); 11851da177e4SLinus Torvalds if (x == NULL) 11861da177e4SLinus Torvalds goto out_noput; 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); 11891da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 11901da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 11911da177e4SLinus Torvalds } else { 119215e47304SEric W. Biederman err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid); 11931da177e4SLinus Torvalds } 11941da177e4SLinus Torvalds xfrm_state_put(x); 11951da177e4SLinus Torvalds out_noput: 11961da177e4SLinus Torvalds return err; 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds 119922e70050SChristoph Hellwig static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, 12005424f32eSThomas Graf struct nlattr **attrs) 12011da177e4SLinus Torvalds { 1202fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 12031da177e4SLinus Torvalds struct xfrm_state *x; 12041da177e4SLinus Torvalds struct xfrm_userspi_info *p; 12051da177e4SLinus Torvalds struct sk_buff *resp_skb; 12061da177e4SLinus Torvalds xfrm_address_t *daddr; 12071da177e4SLinus Torvalds int family; 12081da177e4SLinus Torvalds int err; 12096f26b61eSJamal Hadi Salim u32 mark; 12106f26b61eSJamal Hadi Salim struct xfrm_mark m; 12111da177e4SLinus Torvalds 12127b67c857SThomas Graf p = nlmsg_data(nlh); 1213776e9dd9SFan Du err = verify_spi_info(p->info.id.proto, p->min, p->max); 12141da177e4SLinus Torvalds if (err) 12151da177e4SLinus Torvalds goto out_noput; 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds family = p->info.family; 12181da177e4SLinus Torvalds daddr = &p->info.id.daddr; 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds x = NULL; 12216f26b61eSJamal Hadi Salim 12226f26b61eSJamal Hadi Salim mark = xfrm_mark_get(attrs, &m); 12231da177e4SLinus Torvalds if (p->info.seq) { 12246f26b61eSJamal Hadi Salim x = xfrm_find_acq_byseq(net, mark, p->info.seq); 122570e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) { 12261da177e4SLinus Torvalds xfrm_state_put(x); 12271da177e4SLinus Torvalds x = NULL; 12281da177e4SLinus Torvalds } 12291da177e4SLinus Torvalds } 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds if (!x) 12326f26b61eSJamal Hadi Salim x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, 12331da177e4SLinus Torvalds p->info.id.proto, daddr, 12341da177e4SLinus Torvalds &p->info.saddr, 1, 12351da177e4SLinus Torvalds family); 12361da177e4SLinus Torvalds err = -ENOENT; 12371da177e4SLinus Torvalds if (x == NULL) 12381da177e4SLinus Torvalds goto out_noput; 12391da177e4SLinus Torvalds 1240658b219eSHerbert Xu err = xfrm_alloc_spi(x, p->min, p->max); 1241658b219eSHerbert Xu if (err) 1242658b219eSHerbert Xu goto out; 12431da177e4SLinus Torvalds 12441da177e4SLinus Torvalds resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); 12451da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 12461da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 12471da177e4SLinus Torvalds goto out; 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds 125015e47304SEric W. Biederman err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid); 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds out: 12531da177e4SLinus Torvalds xfrm_state_put(x); 12541da177e4SLinus Torvalds out_noput: 12551da177e4SLinus Torvalds return err; 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds 1258b798a9edSJamal Hadi Salim static int verify_policy_dir(u8 dir) 12591da177e4SLinus Torvalds { 12601da177e4SLinus Torvalds switch (dir) { 12611da177e4SLinus Torvalds case XFRM_POLICY_IN: 12621da177e4SLinus Torvalds case XFRM_POLICY_OUT: 12631da177e4SLinus Torvalds case XFRM_POLICY_FWD: 12641da177e4SLinus Torvalds break; 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds default: 12671da177e4SLinus Torvalds return -EINVAL; 12683ff50b79SStephen Hemminger } 12691da177e4SLinus Torvalds 12701da177e4SLinus Torvalds return 0; 12711da177e4SLinus Torvalds } 12721da177e4SLinus Torvalds 1273b798a9edSJamal Hadi Salim static int verify_policy_type(u8 type) 1274f7b6983fSMasahide NAKAMURA { 1275f7b6983fSMasahide NAKAMURA switch (type) { 1276f7b6983fSMasahide NAKAMURA case XFRM_POLICY_TYPE_MAIN: 1277f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 1278f7b6983fSMasahide NAKAMURA case XFRM_POLICY_TYPE_SUB: 1279f7b6983fSMasahide NAKAMURA #endif 1280f7b6983fSMasahide NAKAMURA break; 1281f7b6983fSMasahide NAKAMURA 1282f7b6983fSMasahide NAKAMURA default: 1283f7b6983fSMasahide NAKAMURA return -EINVAL; 12843ff50b79SStephen Hemminger } 1285f7b6983fSMasahide NAKAMURA 1286f7b6983fSMasahide NAKAMURA return 0; 1287f7b6983fSMasahide NAKAMURA } 1288f7b6983fSMasahide NAKAMURA 12891da177e4SLinus Torvalds static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) 12901da177e4SLinus Torvalds { 1291e682adf0SFan Du int ret; 1292e682adf0SFan Du 12931da177e4SLinus Torvalds switch (p->share) { 12941da177e4SLinus Torvalds case XFRM_SHARE_ANY: 12951da177e4SLinus Torvalds case XFRM_SHARE_SESSION: 12961da177e4SLinus Torvalds case XFRM_SHARE_USER: 12971da177e4SLinus Torvalds case XFRM_SHARE_UNIQUE: 12981da177e4SLinus Torvalds break; 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds default: 13011da177e4SLinus Torvalds return -EINVAL; 13023ff50b79SStephen Hemminger } 13031da177e4SLinus Torvalds 13041da177e4SLinus Torvalds switch (p->action) { 13051da177e4SLinus Torvalds case XFRM_POLICY_ALLOW: 13061da177e4SLinus Torvalds case XFRM_POLICY_BLOCK: 13071da177e4SLinus Torvalds break; 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds default: 13101da177e4SLinus Torvalds return -EINVAL; 13113ff50b79SStephen Hemminger } 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds switch (p->sel.family) { 13141da177e4SLinus Torvalds case AF_INET: 13151da177e4SLinus Torvalds break; 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds case AF_INET6: 1318dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 13191da177e4SLinus Torvalds break; 13201da177e4SLinus Torvalds #else 13211da177e4SLinus Torvalds return -EAFNOSUPPORT; 13221da177e4SLinus Torvalds #endif 13231da177e4SLinus Torvalds 13241da177e4SLinus Torvalds default: 13251da177e4SLinus Torvalds return -EINVAL; 13263ff50b79SStephen Hemminger } 13271da177e4SLinus Torvalds 1328e682adf0SFan Du ret = verify_policy_dir(p->dir); 1329e682adf0SFan Du if (ret) 1330e682adf0SFan Du return ret; 1331e682adf0SFan Du if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir)) 1332e682adf0SFan Du return -EINVAL; 1333e682adf0SFan Du 1334e682adf0SFan Du return 0; 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13375424f32eSThomas Graf static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs) 1338df71837dSTrent Jaeger { 13395424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 1340df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 1341df71837dSTrent Jaeger 1342df71837dSTrent Jaeger if (!rt) 1343df71837dSTrent Jaeger return 0; 1344df71837dSTrent Jaeger 13455424f32eSThomas Graf uctx = nla_data(rt); 134652a4c640SNikolay Aleksandrov return security_xfrm_policy_alloc(&pol->security, uctx, GFP_KERNEL); 1347df71837dSTrent Jaeger } 1348df71837dSTrent Jaeger 13491da177e4SLinus Torvalds static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, 13501da177e4SLinus Torvalds int nr) 13511da177e4SLinus Torvalds { 13521da177e4SLinus Torvalds int i; 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds xp->xfrm_nr = nr; 13551da177e4SLinus Torvalds for (i = 0; i < nr; i++, ut++) { 13561da177e4SLinus Torvalds struct xfrm_tmpl *t = &xp->xfrm_vec[i]; 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds memcpy(&t->id, &ut->id, sizeof(struct xfrm_id)); 13591da177e4SLinus Torvalds memcpy(&t->saddr, &ut->saddr, 13601da177e4SLinus Torvalds sizeof(xfrm_address_t)); 13611da177e4SLinus Torvalds t->reqid = ut->reqid; 13621da177e4SLinus Torvalds t->mode = ut->mode; 13631da177e4SLinus Torvalds t->share = ut->share; 13641da177e4SLinus Torvalds t->optional = ut->optional; 13651da177e4SLinus Torvalds t->aalgos = ut->aalgos; 13661da177e4SLinus Torvalds t->ealgos = ut->ealgos; 13671da177e4SLinus Torvalds t->calgos = ut->calgos; 1368c5d18e98SHerbert Xu /* If all masks are ~0, then we allow all algorithms. */ 1369c5d18e98SHerbert Xu t->allalgs = !~(t->aalgos & t->ealgos & t->calgos); 13708511d01dSMiika Komu t->encap_family = ut->family; 13711da177e4SLinus Torvalds } 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds 1374b4ad86bfSDavid S. Miller static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) 1375b4ad86bfSDavid S. Miller { 1376b4ad86bfSDavid S. Miller int i; 1377b4ad86bfSDavid S. Miller 1378b4ad86bfSDavid S. Miller if (nr > XFRM_MAX_DEPTH) 1379b4ad86bfSDavid S. Miller return -EINVAL; 1380b4ad86bfSDavid S. Miller 1381b4ad86bfSDavid S. Miller for (i = 0; i < nr; i++) { 1382b4ad86bfSDavid S. Miller /* We never validated the ut->family value, so many 1383b4ad86bfSDavid S. Miller * applications simply leave it at zero. The check was 1384b4ad86bfSDavid S. Miller * never made and ut->family was ignored because all 1385b4ad86bfSDavid S. Miller * templates could be assumed to have the same family as 1386b4ad86bfSDavid S. Miller * the policy itself. Now that we will have ipv4-in-ipv6 1387b4ad86bfSDavid S. Miller * and ipv6-in-ipv4 tunnels, this is no longer true. 1388b4ad86bfSDavid S. Miller */ 1389b4ad86bfSDavid S. Miller if (!ut[i].family) 1390b4ad86bfSDavid S. Miller ut[i].family = family; 1391b4ad86bfSDavid S. Miller 1392b4ad86bfSDavid S. Miller switch (ut[i].family) { 1393b4ad86bfSDavid S. Miller case AF_INET: 1394b4ad86bfSDavid S. Miller break; 1395dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 1396b4ad86bfSDavid S. Miller case AF_INET6: 1397b4ad86bfSDavid S. Miller break; 1398b4ad86bfSDavid S. Miller #endif 1399b4ad86bfSDavid S. Miller default: 1400b4ad86bfSDavid S. Miller return -EINVAL; 14013ff50b79SStephen Hemminger } 1402b4ad86bfSDavid S. Miller } 1403b4ad86bfSDavid S. Miller 1404b4ad86bfSDavid S. Miller return 0; 1405b4ad86bfSDavid S. Miller } 1406b4ad86bfSDavid S. Miller 14075424f32eSThomas Graf static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs) 14081da177e4SLinus Torvalds { 14095424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_TMPL]; 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds if (!rt) { 14121da177e4SLinus Torvalds pol->xfrm_nr = 0; 14131da177e4SLinus Torvalds } else { 14145424f32eSThomas Graf struct xfrm_user_tmpl *utmpl = nla_data(rt); 14155424f32eSThomas Graf int nr = nla_len(rt) / sizeof(*utmpl); 1416b4ad86bfSDavid S. Miller int err; 14171da177e4SLinus Torvalds 1418b4ad86bfSDavid S. Miller err = validate_tmpl(nr, utmpl, pol->family); 1419b4ad86bfSDavid S. Miller if (err) 1420b4ad86bfSDavid S. Miller return err; 14211da177e4SLinus Torvalds 14225424f32eSThomas Graf copy_templates(pol, utmpl, nr); 14231da177e4SLinus Torvalds } 14241da177e4SLinus Torvalds return 0; 14251da177e4SLinus Torvalds } 14261da177e4SLinus Torvalds 14275424f32eSThomas Graf static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs) 1428f7b6983fSMasahide NAKAMURA { 14295424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_POLICY_TYPE]; 1430f7b6983fSMasahide NAKAMURA struct xfrm_userpolicy_type *upt; 1431b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 1432f7b6983fSMasahide NAKAMURA int err; 1433f7b6983fSMasahide NAKAMURA 1434f7b6983fSMasahide NAKAMURA if (rt) { 14355424f32eSThomas Graf upt = nla_data(rt); 1436f7b6983fSMasahide NAKAMURA type = upt->type; 1437f7b6983fSMasahide NAKAMURA } 1438f7b6983fSMasahide NAKAMURA 1439f7b6983fSMasahide NAKAMURA err = verify_policy_type(type); 1440f7b6983fSMasahide NAKAMURA if (err) 1441f7b6983fSMasahide NAKAMURA return err; 1442f7b6983fSMasahide NAKAMURA 1443f7b6983fSMasahide NAKAMURA *tp = type; 1444f7b6983fSMasahide NAKAMURA return 0; 1445f7b6983fSMasahide NAKAMURA } 1446f7b6983fSMasahide NAKAMURA 14471da177e4SLinus Torvalds static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) 14481da177e4SLinus Torvalds { 14491da177e4SLinus Torvalds xp->priority = p->priority; 14501da177e4SLinus Torvalds xp->index = p->index; 14511da177e4SLinus Torvalds memcpy(&xp->selector, &p->sel, sizeof(xp->selector)); 14521da177e4SLinus Torvalds memcpy(&xp->lft, &p->lft, sizeof(xp->lft)); 14531da177e4SLinus Torvalds xp->action = p->action; 14541da177e4SLinus Torvalds xp->flags = p->flags; 14551da177e4SLinus Torvalds xp->family = p->sel.family; 14561da177e4SLinus Torvalds /* XXX xp->share = p->share; */ 14571da177e4SLinus Torvalds } 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir) 14601da177e4SLinus Torvalds { 14617b789836SMathias Krause memset(p, 0, sizeof(*p)); 14621da177e4SLinus Torvalds memcpy(&p->sel, &xp->selector, sizeof(p->sel)); 14631da177e4SLinus Torvalds memcpy(&p->lft, &xp->lft, sizeof(p->lft)); 14641da177e4SLinus Torvalds memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); 14651da177e4SLinus Torvalds p->priority = xp->priority; 14661da177e4SLinus Torvalds p->index = xp->index; 14671da177e4SLinus Torvalds p->sel.family = xp->family; 14681da177e4SLinus Torvalds p->dir = dir; 14691da177e4SLinus Torvalds p->action = xp->action; 14701da177e4SLinus Torvalds p->flags = xp->flags; 14711da177e4SLinus Torvalds p->share = XFRM_SHARE_ANY; /* XXX xp->share */ 14721da177e4SLinus Torvalds } 14731da177e4SLinus Torvalds 1474fc34acd3SAlexey Dobriyan static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp) 14751da177e4SLinus Torvalds { 1476fc34acd3SAlexey Dobriyan struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL); 14771da177e4SLinus Torvalds int err; 14781da177e4SLinus Torvalds 14791da177e4SLinus Torvalds if (!xp) { 14801da177e4SLinus Torvalds *errp = -ENOMEM; 14811da177e4SLinus Torvalds return NULL; 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds 14841da177e4SLinus Torvalds copy_from_user_policy(xp, p); 1485df71837dSTrent Jaeger 148635a7aa08SThomas Graf err = copy_from_user_policy_type(&xp->type, attrs); 1487f7b6983fSMasahide NAKAMURA if (err) 1488f7b6983fSMasahide NAKAMURA goto error; 1489f7b6983fSMasahide NAKAMURA 149035a7aa08SThomas Graf if (!(err = copy_from_user_tmpl(xp, attrs))) 149135a7aa08SThomas Graf err = copy_from_user_sec_ctx(xp, attrs); 1492f7b6983fSMasahide NAKAMURA if (err) 1493f7b6983fSMasahide NAKAMURA goto error; 14941da177e4SLinus Torvalds 1495295fae56SJamal Hadi Salim xfrm_mark_get(attrs, &xp->mark); 1496295fae56SJamal Hadi Salim 14971da177e4SLinus Torvalds return xp; 1498f7b6983fSMasahide NAKAMURA error: 1499f7b6983fSMasahide NAKAMURA *errp = err; 150012a169e7SHerbert Xu xp->walk.dead = 1; 150164c31b3fSWANG Cong xfrm_policy_destroy(xp); 1502f7b6983fSMasahide NAKAMURA return NULL; 15031da177e4SLinus Torvalds } 15041da177e4SLinus Torvalds 150522e70050SChristoph Hellwig static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, 15065424f32eSThomas Graf struct nlattr **attrs) 15071da177e4SLinus Torvalds { 1508fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 15097b67c857SThomas Graf struct xfrm_userpolicy_info *p = nlmsg_data(nlh); 15101da177e4SLinus Torvalds struct xfrm_policy *xp; 151126b15dadSJamal Hadi Salim struct km_event c; 15121da177e4SLinus Torvalds int err; 15131da177e4SLinus Torvalds int excl; 15141da177e4SLinus Torvalds 15151da177e4SLinus Torvalds err = verify_newpolicy_info(p); 15161da177e4SLinus Torvalds if (err) 15171da177e4SLinus Torvalds return err; 151835a7aa08SThomas Graf err = verify_sec_ctx_len(attrs); 1519df71837dSTrent Jaeger if (err) 1520df71837dSTrent Jaeger return err; 15211da177e4SLinus Torvalds 1522fc34acd3SAlexey Dobriyan xp = xfrm_policy_construct(net, p, attrs, &err); 15231da177e4SLinus Torvalds if (!xp) 15241da177e4SLinus Torvalds return err; 15251da177e4SLinus Torvalds 152625985edcSLucas De Marchi /* shouldn't excl be based on nlh flags?? 152726b15dadSJamal Hadi Salim * Aha! this is anti-netlink really i.e more pfkey derived 152826b15dadSJamal Hadi Salim * in netlink excl is a flag and you wouldnt need 152926b15dadSJamal Hadi Salim * a type XFRM_MSG_UPDPOLICY - JHS */ 15301da177e4SLinus Torvalds excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; 15311da177e4SLinus Torvalds err = xfrm_policy_insert(p->dir, xp, excl); 15322e71029eSTetsuo Handa xfrm_audit_policy_add(xp, err ? 0 : 1, true); 1533161a09e7SJoy Latten 15341da177e4SLinus Torvalds if (err) { 153503e1ad7bSPaul Moore security_xfrm_policy_free(xp->security); 15361da177e4SLinus Torvalds kfree(xp); 15371da177e4SLinus Torvalds return err; 15381da177e4SLinus Torvalds } 15391da177e4SLinus Torvalds 1540f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 154126b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 154215e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 154326b15dadSJamal Hadi Salim km_policy_notify(xp, p->dir, &c); 154426b15dadSJamal Hadi Salim 15451da177e4SLinus Torvalds xfrm_pol_put(xp); 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds return 0; 15481da177e4SLinus Torvalds } 15491da177e4SLinus Torvalds 15501da177e4SLinus Torvalds static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb) 15511da177e4SLinus Torvalds { 15521da177e4SLinus Torvalds struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH]; 15531da177e4SLinus Torvalds int i; 15541da177e4SLinus Torvalds 15551da177e4SLinus Torvalds if (xp->xfrm_nr == 0) 15561da177e4SLinus Torvalds return 0; 15571da177e4SLinus Torvalds 15581da177e4SLinus Torvalds for (i = 0; i < xp->xfrm_nr; i++) { 15591da177e4SLinus Torvalds struct xfrm_user_tmpl *up = &vec[i]; 15601da177e4SLinus Torvalds struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; 15611da177e4SLinus Torvalds 15621f86840fSMathias Krause memset(up, 0, sizeof(*up)); 15631da177e4SLinus Torvalds memcpy(&up->id, &kp->id, sizeof(up->id)); 15648511d01dSMiika Komu up->family = kp->encap_family; 15651da177e4SLinus Torvalds memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); 15661da177e4SLinus Torvalds up->reqid = kp->reqid; 15671da177e4SLinus Torvalds up->mode = kp->mode; 15681da177e4SLinus Torvalds up->share = kp->share; 15691da177e4SLinus Torvalds up->optional = kp->optional; 15701da177e4SLinus Torvalds up->aalgos = kp->aalgos; 15711da177e4SLinus Torvalds up->ealgos = kp->ealgos; 15721da177e4SLinus Torvalds up->calgos = kp->calgos; 15731da177e4SLinus Torvalds } 15741da177e4SLinus Torvalds 1575c0144beaSThomas Graf return nla_put(skb, XFRMA_TMPL, 1576c0144beaSThomas Graf sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec); 1577df71837dSTrent Jaeger } 1578df71837dSTrent Jaeger 15790d681623SSerge Hallyn static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) 15800d681623SSerge Hallyn { 15810d681623SSerge Hallyn if (x->security) { 15820d681623SSerge Hallyn return copy_sec_ctx(x->security, skb); 15830d681623SSerge Hallyn } 15840d681623SSerge Hallyn return 0; 15850d681623SSerge Hallyn } 15860d681623SSerge Hallyn 15870d681623SSerge Hallyn static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) 15880d681623SSerge Hallyn { 15891d1e34ddSDavid S. Miller if (xp->security) 15900d681623SSerge Hallyn return copy_sec_ctx(xp->security, skb); 15910d681623SSerge Hallyn return 0; 15920d681623SSerge Hallyn } 1593cfbfd45aSThomas Graf static inline size_t userpolicy_type_attrsize(void) 1594cfbfd45aSThomas Graf { 1595cfbfd45aSThomas Graf #ifdef CONFIG_XFRM_SUB_POLICY 1596cfbfd45aSThomas Graf return nla_total_size(sizeof(struct xfrm_userpolicy_type)); 1597cfbfd45aSThomas Graf #else 1598cfbfd45aSThomas Graf return 0; 1599cfbfd45aSThomas Graf #endif 1600cfbfd45aSThomas Graf } 16010d681623SSerge Hallyn 1602f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 1603b798a9edSJamal Hadi Salim static int copy_to_user_policy_type(u8 type, struct sk_buff *skb) 1604f7b6983fSMasahide NAKAMURA { 1605c0144beaSThomas Graf struct xfrm_userpolicy_type upt = { 1606c0144beaSThomas Graf .type = type, 1607c0144beaSThomas Graf }; 1608f7b6983fSMasahide NAKAMURA 1609c0144beaSThomas Graf return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); 1610f7b6983fSMasahide NAKAMURA } 1611f7b6983fSMasahide NAKAMURA 1612f7b6983fSMasahide NAKAMURA #else 1613b798a9edSJamal Hadi Salim static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb) 1614f7b6983fSMasahide NAKAMURA { 1615f7b6983fSMasahide NAKAMURA return 0; 1616f7b6983fSMasahide NAKAMURA } 1617f7b6983fSMasahide NAKAMURA #endif 1618f7b6983fSMasahide NAKAMURA 16191da177e4SLinus Torvalds static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) 16201da177e4SLinus Torvalds { 16211da177e4SLinus Torvalds struct xfrm_dump_info *sp = ptr; 16221da177e4SLinus Torvalds struct xfrm_userpolicy_info *p; 16231da177e4SLinus Torvalds struct sk_buff *in_skb = sp->in_skb; 16241da177e4SLinus Torvalds struct sk_buff *skb = sp->out_skb; 16251da177e4SLinus Torvalds struct nlmsghdr *nlh; 16261d1e34ddSDavid S. Miller int err; 16271da177e4SLinus Torvalds 162815e47304SEric W. Biederman nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq, 162979b8b7f4SThomas Graf XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); 163079b8b7f4SThomas Graf if (nlh == NULL) 163179b8b7f4SThomas Graf return -EMSGSIZE; 16321da177e4SLinus Torvalds 16337b67c857SThomas Graf p = nlmsg_data(nlh); 16341da177e4SLinus Torvalds copy_to_user_policy(xp, p, dir); 16351d1e34ddSDavid S. Miller err = copy_to_user_tmpl(xp, skb); 16361d1e34ddSDavid S. Miller if (!err) 16371d1e34ddSDavid S. Miller err = copy_to_user_sec_ctx(xp, skb); 16381d1e34ddSDavid S. Miller if (!err) 16391d1e34ddSDavid S. Miller err = copy_to_user_policy_type(xp->type, skb); 16401d1e34ddSDavid S. Miller if (!err) 16411d1e34ddSDavid S. Miller err = xfrm_mark_put(skb, &xp->mark); 16421d1e34ddSDavid S. Miller if (err) { 16431d1e34ddSDavid S. Miller nlmsg_cancel(skb, nlh); 16441d1e34ddSDavid S. Miller return err; 16451d1e34ddSDavid S. Miller } 16469825069dSThomas Graf nlmsg_end(skb, nlh); 16471da177e4SLinus Torvalds return 0; 16481da177e4SLinus Torvalds } 16491da177e4SLinus Torvalds 16504c563f76STimo Teras static int xfrm_dump_policy_done(struct netlink_callback *cb) 16514c563f76STimo Teras { 16524c563f76STimo Teras struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; 1653283bc9f3SFan Du struct net *net = sock_net(cb->skb->sk); 16544c563f76STimo Teras 1655283bc9f3SFan Du xfrm_policy_walk_done(walk, net); 16564c563f76STimo Teras return 0; 16574c563f76STimo Teras } 16584c563f76STimo Teras 16591da177e4SLinus Torvalds static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) 16601da177e4SLinus Torvalds { 1661fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 16624c563f76STimo Teras struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; 16631da177e4SLinus Torvalds struct xfrm_dump_info info; 16641da177e4SLinus Torvalds 16654c563f76STimo Teras BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > 16664c563f76STimo Teras sizeof(cb->args) - sizeof(cb->args[0])); 16674c563f76STimo Teras 16681da177e4SLinus Torvalds info.in_skb = cb->skb; 16691da177e4SLinus Torvalds info.out_skb = skb; 16701da177e4SLinus Torvalds info.nlmsg_seq = cb->nlh->nlmsg_seq; 16711da177e4SLinus Torvalds info.nlmsg_flags = NLM_F_MULTI; 16724c563f76STimo Teras 16734c563f76STimo Teras if (!cb->args[0]) { 16744c563f76STimo Teras cb->args[0] = 1; 16754c563f76STimo Teras xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); 16764c563f76STimo Teras } 16774c563f76STimo Teras 1678fc34acd3SAlexey Dobriyan (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); 16791da177e4SLinus Torvalds 16801da177e4SLinus Torvalds return skb->len; 16811da177e4SLinus Torvalds } 16821da177e4SLinus Torvalds 16831da177e4SLinus Torvalds static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, 16841da177e4SLinus Torvalds struct xfrm_policy *xp, 16851da177e4SLinus Torvalds int dir, u32 seq) 16861da177e4SLinus Torvalds { 16871da177e4SLinus Torvalds struct xfrm_dump_info info; 16881da177e4SLinus Torvalds struct sk_buff *skb; 1689c2546372SMathias Krause int err; 16901da177e4SLinus Torvalds 16917deb2264SThomas Graf skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 16921da177e4SLinus Torvalds if (!skb) 16931da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 16941da177e4SLinus Torvalds 16951da177e4SLinus Torvalds info.in_skb = in_skb; 16961da177e4SLinus Torvalds info.out_skb = skb; 16971da177e4SLinus Torvalds info.nlmsg_seq = seq; 16981da177e4SLinus Torvalds info.nlmsg_flags = 0; 16991da177e4SLinus Torvalds 1700c2546372SMathias Krause err = dump_one_policy(xp, dir, 0, &info); 1701c2546372SMathias Krause if (err) { 17021da177e4SLinus Torvalds kfree_skb(skb); 1703c2546372SMathias Krause return ERR_PTR(err); 17041da177e4SLinus Torvalds } 17051da177e4SLinus Torvalds 17061da177e4SLinus Torvalds return skb; 17071da177e4SLinus Torvalds } 17081da177e4SLinus Torvalds 170922e70050SChristoph Hellwig static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, 17105424f32eSThomas Graf struct nlattr **attrs) 17111da177e4SLinus Torvalds { 1712fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 17131da177e4SLinus Torvalds struct xfrm_policy *xp; 17141da177e4SLinus Torvalds struct xfrm_userpolicy_id *p; 1715b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 17161da177e4SLinus Torvalds int err; 171726b15dadSJamal Hadi Salim struct km_event c; 17181da177e4SLinus Torvalds int delete; 1719295fae56SJamal Hadi Salim struct xfrm_mark m; 1720295fae56SJamal Hadi Salim u32 mark = xfrm_mark_get(attrs, &m); 17211da177e4SLinus Torvalds 17227b67c857SThomas Graf p = nlmsg_data(nlh); 17231da177e4SLinus Torvalds delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; 17241da177e4SLinus Torvalds 172535a7aa08SThomas Graf err = copy_from_user_policy_type(&type, attrs); 1726f7b6983fSMasahide NAKAMURA if (err) 1727f7b6983fSMasahide NAKAMURA return err; 1728f7b6983fSMasahide NAKAMURA 17291da177e4SLinus Torvalds err = verify_policy_dir(p->dir); 17301da177e4SLinus Torvalds if (err) 17311da177e4SLinus Torvalds return err; 17321da177e4SLinus Torvalds 17331da177e4SLinus Torvalds if (p->index) 1734295fae56SJamal Hadi Salim xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err); 1735df71837dSTrent Jaeger else { 17365424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 173703e1ad7bSPaul Moore struct xfrm_sec_ctx *ctx; 1738df71837dSTrent Jaeger 173935a7aa08SThomas Graf err = verify_sec_ctx_len(attrs); 1740df71837dSTrent Jaeger if (err) 1741df71837dSTrent Jaeger return err; 1742df71837dSTrent Jaeger 17432c8dd116SDenis V. Lunev ctx = NULL; 1744df71837dSTrent Jaeger if (rt) { 17455424f32eSThomas Graf struct xfrm_user_sec_ctx *uctx = nla_data(rt); 1746df71837dSTrent Jaeger 174752a4c640SNikolay Aleksandrov err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL); 174803e1ad7bSPaul Moore if (err) 1749df71837dSTrent Jaeger return err; 17502c8dd116SDenis V. Lunev } 1751295fae56SJamal Hadi Salim xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel, 17526f26b61eSJamal Hadi Salim ctx, delete, &err); 175303e1ad7bSPaul Moore security_xfrm_policy_free(ctx); 1754df71837dSTrent Jaeger } 17551da177e4SLinus Torvalds if (xp == NULL) 17561da177e4SLinus Torvalds return -ENOENT; 17571da177e4SLinus Torvalds 17581da177e4SLinus Torvalds if (!delete) { 17591da177e4SLinus Torvalds struct sk_buff *resp_skb; 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); 17621da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 17631da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 17641da177e4SLinus Torvalds } else { 1765a6483b79SAlexey Dobriyan err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, 176615e47304SEric W. Biederman NETLINK_CB(skb).portid); 17671da177e4SLinus Torvalds } 176826b15dadSJamal Hadi Salim } else { 17692e71029eSTetsuo Handa xfrm_audit_policy_delete(xp, err ? 0 : 1, true); 177013fcfbb0SDavid S. Miller 177113fcfbb0SDavid S. Miller if (err != 0) 1772c8c05a8eSCatherine Zhang goto out; 177313fcfbb0SDavid S. Miller 1774e7443892SHerbert Xu c.data.byid = p->index; 1775f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 177626b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 177715e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 177826b15dadSJamal Hadi Salim km_policy_notify(xp, p->dir, &c); 17791da177e4SLinus Torvalds } 17801da177e4SLinus Torvalds 1781c8c05a8eSCatherine Zhang out: 1782ef41aaa0SEric Paris xfrm_pol_put(xp); 1783e4c17216SPaul Moore if (delete && err == 0) 1784e4c17216SPaul Moore xfrm_garbage_collect(net); 17851da177e4SLinus Torvalds return err; 17861da177e4SLinus Torvalds } 17871da177e4SLinus Torvalds 178822e70050SChristoph Hellwig static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 17895424f32eSThomas Graf struct nlattr **attrs) 17901da177e4SLinus Torvalds { 1791fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 179226b15dadSJamal Hadi Salim struct km_event c; 17937b67c857SThomas Graf struct xfrm_usersa_flush *p = nlmsg_data(nlh); 17944aa2e62cSJoy Latten int err; 17951da177e4SLinus Torvalds 17962e71029eSTetsuo Handa err = xfrm_state_flush(net, p->proto, true); 17979e64cc95SJamal Hadi Salim if (err) { 17989e64cc95SJamal Hadi Salim if (err == -ESRCH) /* empty table */ 17999e64cc95SJamal Hadi Salim return 0; 1800069c474eSDavid S. Miller return err; 18019e64cc95SJamal Hadi Salim } 1802bf08867fSHerbert Xu c.data.proto = p->proto; 1803f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 180426b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 180515e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 18067067802eSAlexey Dobriyan c.net = net; 180726b15dadSJamal Hadi Salim km_state_notify(NULL, &c); 180826b15dadSJamal Hadi Salim 18091da177e4SLinus Torvalds return 0; 18101da177e4SLinus Torvalds } 18111da177e4SLinus Torvalds 1812d8647b79SSteffen Klassert static inline size_t xfrm_aevent_msgsize(struct xfrm_state *x) 18137deb2264SThomas Graf { 1814d8647b79SSteffen Klassert size_t replay_size = x->replay_esn ? 1815d8647b79SSteffen Klassert xfrm_replay_state_esn_len(x->replay_esn) : 1816d8647b79SSteffen Klassert sizeof(struct xfrm_replay_state); 1817d8647b79SSteffen Klassert 18187deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) 1819d8647b79SSteffen Klassert + nla_total_size(replay_size) 1820de95c4a4SNicolas Dichtel + nla_total_size_64bit(sizeof(struct xfrm_lifetime_cur)) 18216f26b61eSJamal Hadi Salim + nla_total_size(sizeof(struct xfrm_mark)) 18227deb2264SThomas Graf + nla_total_size(4) /* XFRM_AE_RTHR */ 18237deb2264SThomas Graf + nla_total_size(4); /* XFRM_AE_ETHR */ 18247deb2264SThomas Graf } 1825d51d081dSJamal Hadi Salim 1826214e005bSDavid S. Miller static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c) 1827d51d081dSJamal Hadi Salim { 1828d51d081dSJamal Hadi Salim struct xfrm_aevent_id *id; 1829d51d081dSJamal Hadi Salim struct nlmsghdr *nlh; 18301d1e34ddSDavid S. Miller int err; 1831d51d081dSJamal Hadi Salim 183215e47304SEric W. Biederman nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0); 183379b8b7f4SThomas Graf if (nlh == NULL) 183479b8b7f4SThomas Graf return -EMSGSIZE; 1835d51d081dSJamal Hadi Salim 18367b67c857SThomas Graf id = nlmsg_data(nlh); 18372b5f6dccSJamal Hadi Salim memcpy(&id->sa_id.daddr, &x->id.daddr, sizeof(x->id.daddr)); 1838d51d081dSJamal Hadi Salim id->sa_id.spi = x->id.spi; 1839d51d081dSJamal Hadi Salim id->sa_id.family = x->props.family; 1840d51d081dSJamal Hadi Salim id->sa_id.proto = x->id.proto; 18412b5f6dccSJamal Hadi Salim memcpy(&id->saddr, &x->props.saddr, sizeof(x->props.saddr)); 18422b5f6dccSJamal Hadi Salim id->reqid = x->props.reqid; 1843d51d081dSJamal Hadi Salim id->flags = c->data.aevent; 1844d51d081dSJamal Hadi Salim 1845d0fde795SDavid S. Miller if (x->replay_esn) { 18461d1e34ddSDavid S. Miller err = nla_put(skb, XFRMA_REPLAY_ESN_VAL, 1847d8647b79SSteffen Klassert xfrm_replay_state_esn_len(x->replay_esn), 18481d1e34ddSDavid S. Miller x->replay_esn); 1849d0fde795SDavid S. Miller } else { 18501d1e34ddSDavid S. Miller err = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), 18511d1e34ddSDavid S. Miller &x->replay); 1852d0fde795SDavid S. Miller } 18531d1e34ddSDavid S. Miller if (err) 18541d1e34ddSDavid S. Miller goto out_cancel; 1855de95c4a4SNicolas Dichtel err = nla_put_64bit(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft, 1856de95c4a4SNicolas Dichtel XFRMA_PAD); 18571d1e34ddSDavid S. Miller if (err) 18581d1e34ddSDavid S. Miller goto out_cancel; 1859d8647b79SSteffen Klassert 18601d1e34ddSDavid S. Miller if (id->flags & XFRM_AE_RTHR) { 18611d1e34ddSDavid S. Miller err = nla_put_u32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff); 18621d1e34ddSDavid S. Miller if (err) 18631d1e34ddSDavid S. Miller goto out_cancel; 18641d1e34ddSDavid S. Miller } 18651d1e34ddSDavid S. Miller if (id->flags & XFRM_AE_ETHR) { 18661d1e34ddSDavid S. Miller err = nla_put_u32(skb, XFRMA_ETIMER_THRESH, 18671d1e34ddSDavid S. Miller x->replay_maxage * 10 / HZ); 18681d1e34ddSDavid S. Miller if (err) 18691d1e34ddSDavid S. Miller goto out_cancel; 18701d1e34ddSDavid S. Miller } 18711d1e34ddSDavid S. Miller err = xfrm_mark_put(skb, &x->mark); 18721d1e34ddSDavid S. Miller if (err) 18731d1e34ddSDavid S. Miller goto out_cancel; 18746f26b61eSJamal Hadi Salim 1875053c095aSJohannes Berg nlmsg_end(skb, nlh); 1876053c095aSJohannes Berg return 0; 1877d51d081dSJamal Hadi Salim 18781d1e34ddSDavid S. Miller out_cancel: 18799825069dSThomas Graf nlmsg_cancel(skb, nlh); 18801d1e34ddSDavid S. Miller return err; 1881d51d081dSJamal Hadi Salim } 1882d51d081dSJamal Hadi Salim 188322e70050SChristoph Hellwig static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, 18845424f32eSThomas Graf struct nlattr **attrs) 1885d51d081dSJamal Hadi Salim { 1886fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 1887d51d081dSJamal Hadi Salim struct xfrm_state *x; 1888d51d081dSJamal Hadi Salim struct sk_buff *r_skb; 1889d51d081dSJamal Hadi Salim int err; 1890d51d081dSJamal Hadi Salim struct km_event c; 18916f26b61eSJamal Hadi Salim u32 mark; 18926f26b61eSJamal Hadi Salim struct xfrm_mark m; 18937b67c857SThomas Graf struct xfrm_aevent_id *p = nlmsg_data(nlh); 1894d51d081dSJamal Hadi Salim struct xfrm_usersa_id *id = &p->sa_id; 1895d51d081dSJamal Hadi Salim 18966f26b61eSJamal Hadi Salim mark = xfrm_mark_get(attrs, &m); 18976f26b61eSJamal Hadi Salim 18986f26b61eSJamal Hadi Salim x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family); 1899d8647b79SSteffen Klassert if (x == NULL) 1900d51d081dSJamal Hadi Salim return -ESRCH; 1901d8647b79SSteffen Klassert 1902d8647b79SSteffen Klassert r_skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC); 1903d8647b79SSteffen Klassert if (r_skb == NULL) { 1904d8647b79SSteffen Klassert xfrm_state_put(x); 1905d8647b79SSteffen Klassert return -ENOMEM; 1906d51d081dSJamal Hadi Salim } 1907d51d081dSJamal Hadi Salim 1908d51d081dSJamal Hadi Salim /* 1909d51d081dSJamal Hadi Salim * XXX: is this lock really needed - none of the other 1910d51d081dSJamal Hadi Salim * gets lock (the concern is things getting updated 1911d51d081dSJamal Hadi Salim * while we are still reading) - jhs 1912d51d081dSJamal Hadi Salim */ 1913d51d081dSJamal Hadi Salim spin_lock_bh(&x->lock); 1914d51d081dSJamal Hadi Salim c.data.aevent = p->flags; 1915d51d081dSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 191615e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 1917d51d081dSJamal Hadi Salim 1918d51d081dSJamal Hadi Salim if (build_aevent(r_skb, x, &c) < 0) 1919d51d081dSJamal Hadi Salim BUG(); 192015e47304SEric W. Biederman err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).portid); 1921d51d081dSJamal Hadi Salim spin_unlock_bh(&x->lock); 1922d51d081dSJamal Hadi Salim xfrm_state_put(x); 1923d51d081dSJamal Hadi Salim return err; 1924d51d081dSJamal Hadi Salim } 1925d51d081dSJamal Hadi Salim 192622e70050SChristoph Hellwig static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, 19275424f32eSThomas Graf struct nlattr **attrs) 1928d51d081dSJamal Hadi Salim { 1929fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 1930d51d081dSJamal Hadi Salim struct xfrm_state *x; 1931d51d081dSJamal Hadi Salim struct km_event c; 1932d51d081dSJamal Hadi Salim int err = -EINVAL; 19336f26b61eSJamal Hadi Salim u32 mark = 0; 19346f26b61eSJamal Hadi Salim struct xfrm_mark m; 19357b67c857SThomas Graf struct xfrm_aevent_id *p = nlmsg_data(nlh); 19365424f32eSThomas Graf struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; 1937d8647b79SSteffen Klassert struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL]; 19385424f32eSThomas Graf struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; 19394e077237SMichael Rossberg struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; 19404e077237SMichael Rossberg struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; 1941d51d081dSJamal Hadi Salim 19424e077237SMichael Rossberg if (!lt && !rp && !re && !et && !rt) 1943d51d081dSJamal Hadi Salim return err; 1944d51d081dSJamal Hadi Salim 1945d51d081dSJamal Hadi Salim /* pedantic mode - thou shalt sayeth replaceth */ 1946d51d081dSJamal Hadi Salim if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) 1947d51d081dSJamal Hadi Salim return err; 1948d51d081dSJamal Hadi Salim 19496f26b61eSJamal Hadi Salim mark = xfrm_mark_get(attrs, &m); 19506f26b61eSJamal Hadi Salim 19516f26b61eSJamal Hadi Salim x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); 1952d51d081dSJamal Hadi Salim if (x == NULL) 1953d51d081dSJamal Hadi Salim return -ESRCH; 1954d51d081dSJamal Hadi Salim 1955d51d081dSJamal Hadi Salim if (x->km.state != XFRM_STATE_VALID) 1956d51d081dSJamal Hadi Salim goto out; 1957d51d081dSJamal Hadi Salim 19584479ff76SSteffen Klassert err = xfrm_replay_verify_len(x->replay_esn, re); 1959e2b19125SSteffen Klassert if (err) 1960e2b19125SSteffen Klassert goto out; 1961e2b19125SSteffen Klassert 1962d51d081dSJamal Hadi Salim spin_lock_bh(&x->lock); 1963e3ac104dSMathias Krause xfrm_update_ae_params(x, attrs, 1); 1964d51d081dSJamal Hadi Salim spin_unlock_bh(&x->lock); 1965d51d081dSJamal Hadi Salim 1966d51d081dSJamal Hadi Salim c.event = nlh->nlmsg_type; 1967d51d081dSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 196815e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 1969d51d081dSJamal Hadi Salim c.data.aevent = XFRM_AE_CU; 1970d51d081dSJamal Hadi Salim km_state_notify(x, &c); 1971d51d081dSJamal Hadi Salim err = 0; 1972d51d081dSJamal Hadi Salim out: 1973d51d081dSJamal Hadi Salim xfrm_state_put(x); 1974d51d081dSJamal Hadi Salim return err; 1975d51d081dSJamal Hadi Salim } 1976d51d081dSJamal Hadi Salim 197722e70050SChristoph Hellwig static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, 19785424f32eSThomas Graf struct nlattr **attrs) 19791da177e4SLinus Torvalds { 1980fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 198126b15dadSJamal Hadi Salim struct km_event c; 1982b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 1983f7b6983fSMasahide NAKAMURA int err; 198426b15dadSJamal Hadi Salim 198535a7aa08SThomas Graf err = copy_from_user_policy_type(&type, attrs); 1986f7b6983fSMasahide NAKAMURA if (err) 1987f7b6983fSMasahide NAKAMURA return err; 1988f7b6983fSMasahide NAKAMURA 19892e71029eSTetsuo Handa err = xfrm_policy_flush(net, type, true); 19902f1eb65fSJamal Hadi Salim if (err) { 19912f1eb65fSJamal Hadi Salim if (err == -ESRCH) /* empty table */ 19922f1eb65fSJamal Hadi Salim return 0; 1993069c474eSDavid S. Miller return err; 19942f1eb65fSJamal Hadi Salim } 19952f1eb65fSJamal Hadi Salim 1996f7b6983fSMasahide NAKAMURA c.data.type = type; 1997f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 199826b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 199915e47304SEric W. Biederman c.portid = nlh->nlmsg_pid; 20007067802eSAlexey Dobriyan c.net = net; 200126b15dadSJamal Hadi Salim km_policy_notify(NULL, 0, &c); 20021da177e4SLinus Torvalds return 0; 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds 200522e70050SChristoph Hellwig static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, 20065424f32eSThomas Graf struct nlattr **attrs) 20076c5c8ca7SJamal Hadi Salim { 2008fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 20096c5c8ca7SJamal Hadi Salim struct xfrm_policy *xp; 20107b67c857SThomas Graf struct xfrm_user_polexpire *up = nlmsg_data(nlh); 20116c5c8ca7SJamal Hadi Salim struct xfrm_userpolicy_info *p = &up->pol; 2012b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 20136c5c8ca7SJamal Hadi Salim int err = -ENOENT; 2014295fae56SJamal Hadi Salim struct xfrm_mark m; 2015295fae56SJamal Hadi Salim u32 mark = xfrm_mark_get(attrs, &m); 20166c5c8ca7SJamal Hadi Salim 201735a7aa08SThomas Graf err = copy_from_user_policy_type(&type, attrs); 2018f7b6983fSMasahide NAKAMURA if (err) 2019f7b6983fSMasahide NAKAMURA return err; 2020f7b6983fSMasahide NAKAMURA 2021c8bf4d04STimo Teräs err = verify_policy_dir(p->dir); 2022c8bf4d04STimo Teräs if (err) 2023c8bf4d04STimo Teräs return err; 2024c8bf4d04STimo Teräs 20256c5c8ca7SJamal Hadi Salim if (p->index) 2026295fae56SJamal Hadi Salim xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err); 20276c5c8ca7SJamal Hadi Salim else { 20285424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 202903e1ad7bSPaul Moore struct xfrm_sec_ctx *ctx; 20306c5c8ca7SJamal Hadi Salim 203135a7aa08SThomas Graf err = verify_sec_ctx_len(attrs); 20326c5c8ca7SJamal Hadi Salim if (err) 20336c5c8ca7SJamal Hadi Salim return err; 20346c5c8ca7SJamal Hadi Salim 20352c8dd116SDenis V. Lunev ctx = NULL; 20366c5c8ca7SJamal Hadi Salim if (rt) { 20375424f32eSThomas Graf struct xfrm_user_sec_ctx *uctx = nla_data(rt); 20386c5c8ca7SJamal Hadi Salim 203952a4c640SNikolay Aleksandrov err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL); 204003e1ad7bSPaul Moore if (err) 20416c5c8ca7SJamal Hadi Salim return err; 20422c8dd116SDenis V. Lunev } 2043295fae56SJamal Hadi Salim xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, 20446f26b61eSJamal Hadi Salim &p->sel, ctx, 0, &err); 204503e1ad7bSPaul Moore security_xfrm_policy_free(ctx); 20466c5c8ca7SJamal Hadi Salim } 20476c5c8ca7SJamal Hadi Salim if (xp == NULL) 2048ef41aaa0SEric Paris return -ENOENT; 204903e1ad7bSPaul Moore 2050ea2dea9dSTimo Teräs if (unlikely(xp->walk.dead)) 20516c5c8ca7SJamal Hadi Salim goto out; 20526c5c8ca7SJamal Hadi Salim 20536c5c8ca7SJamal Hadi Salim err = 0; 20546c5c8ca7SJamal Hadi Salim if (up->hard) { 20556c5c8ca7SJamal Hadi Salim xfrm_policy_delete(xp, p->dir); 20562e71029eSTetsuo Handa xfrm_audit_policy_delete(xp, 1, true); 20576c5c8ca7SJamal Hadi Salim } 2058c6bb8136SEric W. Biederman km_policy_expired(xp, p->dir, up->hard, nlh->nlmsg_pid); 20596c5c8ca7SJamal Hadi Salim 20606c5c8ca7SJamal Hadi Salim out: 20616c5c8ca7SJamal Hadi Salim xfrm_pol_put(xp); 20626c5c8ca7SJamal Hadi Salim return err; 20636c5c8ca7SJamal Hadi Salim } 20646c5c8ca7SJamal Hadi Salim 206522e70050SChristoph Hellwig static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, 20665424f32eSThomas Graf struct nlattr **attrs) 206753bc6b4dSJamal Hadi Salim { 2068fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 206953bc6b4dSJamal Hadi Salim struct xfrm_state *x; 207053bc6b4dSJamal Hadi Salim int err; 20717b67c857SThomas Graf struct xfrm_user_expire *ue = nlmsg_data(nlh); 207253bc6b4dSJamal Hadi Salim struct xfrm_usersa_info *p = &ue->state; 20736f26b61eSJamal Hadi Salim struct xfrm_mark m; 2074928497f0SNicolas Dichtel u32 mark = xfrm_mark_get(attrs, &m); 207553bc6b4dSJamal Hadi Salim 20766f26b61eSJamal Hadi Salim x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family); 207753bc6b4dSJamal Hadi Salim 20783a765aa5SDavid S. Miller err = -ENOENT; 207953bc6b4dSJamal Hadi Salim if (x == NULL) 208053bc6b4dSJamal Hadi Salim return err; 208153bc6b4dSJamal Hadi Salim 208253bc6b4dSJamal Hadi Salim spin_lock_bh(&x->lock); 20833a765aa5SDavid S. Miller err = -EINVAL; 208453bc6b4dSJamal Hadi Salim if (x->km.state != XFRM_STATE_VALID) 208553bc6b4dSJamal Hadi Salim goto out; 2086c6bb8136SEric W. Biederman km_state_expired(x, ue->hard, nlh->nlmsg_pid); 208753bc6b4dSJamal Hadi Salim 2088161a09e7SJoy Latten if (ue->hard) { 208953bc6b4dSJamal Hadi Salim __xfrm_state_delete(x); 20902e71029eSTetsuo Handa xfrm_audit_state_delete(x, 1, true); 2091161a09e7SJoy Latten } 20923a765aa5SDavid S. Miller err = 0; 209353bc6b4dSJamal Hadi Salim out: 209453bc6b4dSJamal Hadi Salim spin_unlock_bh(&x->lock); 209553bc6b4dSJamal Hadi Salim xfrm_state_put(x); 209653bc6b4dSJamal Hadi Salim return err; 209753bc6b4dSJamal Hadi Salim } 209853bc6b4dSJamal Hadi Salim 209922e70050SChristoph Hellwig static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, 21005424f32eSThomas Graf struct nlattr **attrs) 2101980ebd25SJamal Hadi Salim { 2102fc34acd3SAlexey Dobriyan struct net *net = sock_net(skb->sk); 2103980ebd25SJamal Hadi Salim struct xfrm_policy *xp; 2104980ebd25SJamal Hadi Salim struct xfrm_user_tmpl *ut; 2105980ebd25SJamal Hadi Salim int i; 21065424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_TMPL]; 21076f26b61eSJamal Hadi Salim struct xfrm_mark mark; 2108980ebd25SJamal Hadi Salim 21097b67c857SThomas Graf struct xfrm_user_acquire *ua = nlmsg_data(nlh); 2110fc34acd3SAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(net); 2111980ebd25SJamal Hadi Salim int err = -ENOMEM; 2112980ebd25SJamal Hadi Salim 2113980ebd25SJamal Hadi Salim if (!x) 2114d8eb9307SIlpo Järvinen goto nomem; 2115980ebd25SJamal Hadi Salim 21166f26b61eSJamal Hadi Salim xfrm_mark_get(attrs, &mark); 21176f26b61eSJamal Hadi Salim 2118980ebd25SJamal Hadi Salim err = verify_newpolicy_info(&ua->policy); 2119d8eb9307SIlpo Järvinen if (err) 212073efc324SVegard Nossum goto free_state; 2121980ebd25SJamal Hadi Salim 2122980ebd25SJamal Hadi Salim /* build an XP */ 2123fc34acd3SAlexey Dobriyan xp = xfrm_policy_construct(net, &ua->policy, attrs, &err); 2124d8eb9307SIlpo Järvinen if (!xp) 2125d8eb9307SIlpo Järvinen goto free_state; 2126980ebd25SJamal Hadi Salim 2127980ebd25SJamal Hadi Salim memcpy(&x->id, &ua->id, sizeof(ua->id)); 2128980ebd25SJamal Hadi Salim memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); 2129980ebd25SJamal Hadi Salim memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); 21306f26b61eSJamal Hadi Salim xp->mark.m = x->mark.m = mark.m; 21316f26b61eSJamal Hadi Salim xp->mark.v = x->mark.v = mark.v; 21325424f32eSThomas Graf ut = nla_data(rt); 2133980ebd25SJamal Hadi Salim /* extract the templates and for each call km_key */ 2134980ebd25SJamal Hadi Salim for (i = 0; i < xp->xfrm_nr; i++, ut++) { 2135980ebd25SJamal Hadi Salim struct xfrm_tmpl *t = &xp->xfrm_vec[i]; 2136980ebd25SJamal Hadi Salim memcpy(&x->id, &t->id, sizeof(x->id)); 2137980ebd25SJamal Hadi Salim x->props.mode = t->mode; 2138980ebd25SJamal Hadi Salim x->props.reqid = t->reqid; 2139980ebd25SJamal Hadi Salim x->props.family = ut->family; 2140980ebd25SJamal Hadi Salim t->aalgos = ua->aalgos; 2141980ebd25SJamal Hadi Salim t->ealgos = ua->ealgos; 2142980ebd25SJamal Hadi Salim t->calgos = ua->calgos; 2143980ebd25SJamal Hadi Salim err = km_query(x, t, xp); 2144980ebd25SJamal Hadi Salim 2145980ebd25SJamal Hadi Salim } 2146980ebd25SJamal Hadi Salim 2147980ebd25SJamal Hadi Salim kfree(x); 2148980ebd25SJamal Hadi Salim kfree(xp); 2149980ebd25SJamal Hadi Salim 2150980ebd25SJamal Hadi Salim return 0; 2151d8eb9307SIlpo Järvinen 2152d8eb9307SIlpo Järvinen free_state: 2153d8eb9307SIlpo Järvinen kfree(x); 2154d8eb9307SIlpo Järvinen nomem: 2155d8eb9307SIlpo Järvinen return err; 2156980ebd25SJamal Hadi Salim } 2157980ebd25SJamal Hadi Salim 21585c79de6eSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 21595c79de6eSShinta Sugimoto static int copy_from_user_migrate(struct xfrm_migrate *ma, 216013c1d189SArnaud Ebalard struct xfrm_kmaddress *k, 21615424f32eSThomas Graf struct nlattr **attrs, int *num) 21625c79de6eSShinta Sugimoto { 21635424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_MIGRATE]; 21645c79de6eSShinta Sugimoto struct xfrm_user_migrate *um; 21655c79de6eSShinta Sugimoto int i, num_migrate; 21665c79de6eSShinta Sugimoto 216713c1d189SArnaud Ebalard if (k != NULL) { 216813c1d189SArnaud Ebalard struct xfrm_user_kmaddress *uk; 216913c1d189SArnaud Ebalard 217013c1d189SArnaud Ebalard uk = nla_data(attrs[XFRMA_KMADDRESS]); 217113c1d189SArnaud Ebalard memcpy(&k->local, &uk->local, sizeof(k->local)); 217213c1d189SArnaud Ebalard memcpy(&k->remote, &uk->remote, sizeof(k->remote)); 217313c1d189SArnaud Ebalard k->family = uk->family; 217413c1d189SArnaud Ebalard k->reserved = uk->reserved; 217513c1d189SArnaud Ebalard } 217613c1d189SArnaud Ebalard 21775424f32eSThomas Graf um = nla_data(rt); 21785424f32eSThomas Graf num_migrate = nla_len(rt) / sizeof(*um); 21795c79de6eSShinta Sugimoto 21805c79de6eSShinta Sugimoto if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH) 21815c79de6eSShinta Sugimoto return -EINVAL; 21825c79de6eSShinta Sugimoto 21835c79de6eSShinta Sugimoto for (i = 0; i < num_migrate; i++, um++, ma++) { 21845c79de6eSShinta Sugimoto memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr)); 21855c79de6eSShinta Sugimoto memcpy(&ma->old_saddr, &um->old_saddr, sizeof(ma->old_saddr)); 21865c79de6eSShinta Sugimoto memcpy(&ma->new_daddr, &um->new_daddr, sizeof(ma->new_daddr)); 21875c79de6eSShinta Sugimoto memcpy(&ma->new_saddr, &um->new_saddr, sizeof(ma->new_saddr)); 21885c79de6eSShinta Sugimoto 21895c79de6eSShinta Sugimoto ma->proto = um->proto; 21905c79de6eSShinta Sugimoto ma->mode = um->mode; 21915c79de6eSShinta Sugimoto ma->reqid = um->reqid; 21925c79de6eSShinta Sugimoto 21935c79de6eSShinta Sugimoto ma->old_family = um->old_family; 21945c79de6eSShinta Sugimoto ma->new_family = um->new_family; 21955c79de6eSShinta Sugimoto } 21965c79de6eSShinta Sugimoto 21975c79de6eSShinta Sugimoto *num = i; 21985c79de6eSShinta Sugimoto return 0; 21995c79de6eSShinta Sugimoto } 22005c79de6eSShinta Sugimoto 22015c79de6eSShinta Sugimoto static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, 22025424f32eSThomas Graf struct nlattr **attrs) 22035c79de6eSShinta Sugimoto { 22047b67c857SThomas Graf struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); 22055c79de6eSShinta Sugimoto struct xfrm_migrate m[XFRM_MAX_DEPTH]; 220613c1d189SArnaud Ebalard struct xfrm_kmaddress km, *kmp; 22075c79de6eSShinta Sugimoto u8 type; 22085c79de6eSShinta Sugimoto int err; 22095c79de6eSShinta Sugimoto int n = 0; 22108d549c4fSFan Du struct net *net = sock_net(skb->sk); 22115c79de6eSShinta Sugimoto 221235a7aa08SThomas Graf if (attrs[XFRMA_MIGRATE] == NULL) 2213cf5cb79fSThomas Graf return -EINVAL; 22145c79de6eSShinta Sugimoto 221513c1d189SArnaud Ebalard kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL; 221613c1d189SArnaud Ebalard 22175424f32eSThomas Graf err = copy_from_user_policy_type(&type, attrs); 22185c79de6eSShinta Sugimoto if (err) 22195c79de6eSShinta Sugimoto return err; 22205c79de6eSShinta Sugimoto 222113c1d189SArnaud Ebalard err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n); 22225c79de6eSShinta Sugimoto if (err) 22235c79de6eSShinta Sugimoto return err; 22245c79de6eSShinta Sugimoto 22255c79de6eSShinta Sugimoto if (!n) 22265c79de6eSShinta Sugimoto return 0; 22275c79de6eSShinta Sugimoto 22288d549c4fSFan Du xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net); 22295c79de6eSShinta Sugimoto 22305c79de6eSShinta Sugimoto return 0; 22315c79de6eSShinta Sugimoto } 22325c79de6eSShinta Sugimoto #else 22335c79de6eSShinta Sugimoto static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, 22345424f32eSThomas Graf struct nlattr **attrs) 22355c79de6eSShinta Sugimoto { 22365c79de6eSShinta Sugimoto return -ENOPROTOOPT; 22375c79de6eSShinta Sugimoto } 22385c79de6eSShinta Sugimoto #endif 22395c79de6eSShinta Sugimoto 22405c79de6eSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 2241183cad12SDavid S. Miller static int copy_to_user_migrate(const struct xfrm_migrate *m, struct sk_buff *skb) 22425c79de6eSShinta Sugimoto { 22435c79de6eSShinta Sugimoto struct xfrm_user_migrate um; 22445c79de6eSShinta Sugimoto 22455c79de6eSShinta Sugimoto memset(&um, 0, sizeof(um)); 22465c79de6eSShinta Sugimoto um.proto = m->proto; 22475c79de6eSShinta Sugimoto um.mode = m->mode; 22485c79de6eSShinta Sugimoto um.reqid = m->reqid; 22495c79de6eSShinta Sugimoto um.old_family = m->old_family; 22505c79de6eSShinta Sugimoto memcpy(&um.old_daddr, &m->old_daddr, sizeof(um.old_daddr)); 22515c79de6eSShinta Sugimoto memcpy(&um.old_saddr, &m->old_saddr, sizeof(um.old_saddr)); 22525c79de6eSShinta Sugimoto um.new_family = m->new_family; 22535c79de6eSShinta Sugimoto memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr)); 22545c79de6eSShinta Sugimoto memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr)); 22555c79de6eSShinta Sugimoto 2256c0144beaSThomas Graf return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); 22575c79de6eSShinta Sugimoto } 22585c79de6eSShinta Sugimoto 2259183cad12SDavid S. Miller static int copy_to_user_kmaddress(const struct xfrm_kmaddress *k, struct sk_buff *skb) 226013c1d189SArnaud Ebalard { 226113c1d189SArnaud Ebalard struct xfrm_user_kmaddress uk; 226213c1d189SArnaud Ebalard 226313c1d189SArnaud Ebalard memset(&uk, 0, sizeof(uk)); 226413c1d189SArnaud Ebalard uk.family = k->family; 226513c1d189SArnaud Ebalard uk.reserved = k->reserved; 226613c1d189SArnaud Ebalard memcpy(&uk.local, &k->local, sizeof(uk.local)); 2267a1caa322SArnaud Ebalard memcpy(&uk.remote, &k->remote, sizeof(uk.remote)); 226813c1d189SArnaud Ebalard 226913c1d189SArnaud Ebalard return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk); 227013c1d189SArnaud Ebalard } 227113c1d189SArnaud Ebalard 227213c1d189SArnaud Ebalard static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma) 22737deb2264SThomas Graf { 22747deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) 227513c1d189SArnaud Ebalard + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0) 22767deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) 22777deb2264SThomas Graf + userpolicy_type_attrsize(); 22787deb2264SThomas Graf } 22797deb2264SThomas Graf 2280183cad12SDavid S. Miller static int build_migrate(struct sk_buff *skb, const struct xfrm_migrate *m, 2281183cad12SDavid S. Miller int num_migrate, const struct xfrm_kmaddress *k, 2282183cad12SDavid S. Miller const struct xfrm_selector *sel, u8 dir, u8 type) 22835c79de6eSShinta Sugimoto { 2284183cad12SDavid S. Miller const struct xfrm_migrate *mp; 22855c79de6eSShinta Sugimoto struct xfrm_userpolicy_id *pol_id; 22865c79de6eSShinta Sugimoto struct nlmsghdr *nlh; 22871d1e34ddSDavid S. Miller int i, err; 22885c79de6eSShinta Sugimoto 228979b8b7f4SThomas Graf nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0); 229079b8b7f4SThomas Graf if (nlh == NULL) 229179b8b7f4SThomas Graf return -EMSGSIZE; 22925c79de6eSShinta Sugimoto 22937b67c857SThomas Graf pol_id = nlmsg_data(nlh); 22945c79de6eSShinta Sugimoto /* copy data from selector, dir, and type to the pol_id */ 22955c79de6eSShinta Sugimoto memset(pol_id, 0, sizeof(*pol_id)); 22965c79de6eSShinta Sugimoto memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); 22975c79de6eSShinta Sugimoto pol_id->dir = dir; 22985c79de6eSShinta Sugimoto 22991d1e34ddSDavid S. Miller if (k != NULL) { 23001d1e34ddSDavid S. Miller err = copy_to_user_kmaddress(k, skb); 23011d1e34ddSDavid S. Miller if (err) 23021d1e34ddSDavid S. Miller goto out_cancel; 23031d1e34ddSDavid S. Miller } 23041d1e34ddSDavid S. Miller err = copy_to_user_policy_type(type, skb); 23051d1e34ddSDavid S. Miller if (err) 23061d1e34ddSDavid S. Miller goto out_cancel; 23075c79de6eSShinta Sugimoto for (i = 0, mp = m ; i < num_migrate; i++, mp++) { 23081d1e34ddSDavid S. Miller err = copy_to_user_migrate(mp, skb); 23091d1e34ddSDavid S. Miller if (err) 23101d1e34ddSDavid S. Miller goto out_cancel; 23115c79de6eSShinta Sugimoto } 23125c79de6eSShinta Sugimoto 2313053c095aSJohannes Berg nlmsg_end(skb, nlh); 2314053c095aSJohannes Berg return 0; 23151d1e34ddSDavid S. Miller 23161d1e34ddSDavid S. Miller out_cancel: 23179825069dSThomas Graf nlmsg_cancel(skb, nlh); 23181d1e34ddSDavid S. Miller return err; 23195c79de6eSShinta Sugimoto } 23205c79de6eSShinta Sugimoto 2321183cad12SDavid S. Miller static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 2322183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_migrate, 2323183cad12SDavid S. Miller const struct xfrm_kmaddress *k) 23245c79de6eSShinta Sugimoto { 2325a6483b79SAlexey Dobriyan struct net *net = &init_net; 23265c79de6eSShinta Sugimoto struct sk_buff *skb; 23275c79de6eSShinta Sugimoto 232813c1d189SArnaud Ebalard skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC); 23295c79de6eSShinta Sugimoto if (skb == NULL) 23305c79de6eSShinta Sugimoto return -ENOMEM; 23315c79de6eSShinta Sugimoto 23325c79de6eSShinta Sugimoto /* build migrate */ 233313c1d189SArnaud Ebalard if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0) 23345c79de6eSShinta Sugimoto BUG(); 23355c79de6eSShinta Sugimoto 233621ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE); 23375c79de6eSShinta Sugimoto } 23385c79de6eSShinta Sugimoto #else 2339183cad12SDavid S. Miller static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 2340183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_migrate, 2341183cad12SDavid S. Miller const struct xfrm_kmaddress *k) 23425c79de6eSShinta Sugimoto { 23435c79de6eSShinta Sugimoto return -ENOPROTOOPT; 23445c79de6eSShinta Sugimoto } 23455c79de6eSShinta Sugimoto #endif 2346d51d081dSJamal Hadi Salim 2347a7bd9a45SThomas Graf #define XMSGSIZE(type) sizeof(struct type) 2348492b558bSThomas Graf 2349492b558bSThomas Graf static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { 235066f9a259SDavid S. Miller [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), 2351492b558bSThomas Graf [XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 2352492b558bSThomas Graf [XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 2353492b558bSThomas Graf [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), 2354492b558bSThomas Graf [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 2355492b558bSThomas Graf [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 2356492b558bSThomas Graf [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info), 2357980ebd25SJamal Hadi Salim [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire), 235853bc6b4dSJamal Hadi Salim [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire), 2359492b558bSThomas Graf [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), 236066f9a259SDavid S. Miller [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), 23616c5c8ca7SJamal Hadi Salim [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), 2362492b558bSThomas Graf [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), 2363a7bd9a45SThomas Graf [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0, 2364d51d081dSJamal Hadi Salim [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 2365d51d081dSJamal Hadi Salim [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 236697a64b45SMasahide NAKAMURA [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), 23675c79de6eSShinta Sugimoto [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 2368a7bd9a45SThomas Graf [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32), 2369880a6fabSChristophe Gouault [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 2370a7bd9a45SThomas Graf [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 23711da177e4SLinus Torvalds }; 23721da177e4SLinus Torvalds 2373492b558bSThomas Graf #undef XMSGSIZE 2374492b558bSThomas Graf 2375cf5cb79fSThomas Graf static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { 2376c28e9304Sjamal [XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)}, 2377c28e9304Sjamal [XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)}, 2378c28e9304Sjamal [XFRMA_LASTUSED] = { .type = NLA_U64}, 2379c28e9304Sjamal [XFRMA_ALG_AUTH_TRUNC] = { .len = sizeof(struct xfrm_algo_auth)}, 23801a6509d9SHerbert Xu [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, 2381cf5cb79fSThomas Graf [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, 2382cf5cb79fSThomas Graf [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, 2383cf5cb79fSThomas Graf [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, 2384cf5cb79fSThomas Graf [XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) }, 2385cf5cb79fSThomas Graf [XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) }, 2386cf5cb79fSThomas Graf [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) }, 2387cf5cb79fSThomas Graf [XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) }, 2388cf5cb79fSThomas Graf [XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) }, 2389cf5cb79fSThomas Graf [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 }, 2390cf5cb79fSThomas Graf [XFRMA_ETIMER_THRESH] = { .type = NLA_U32 }, 2391cf5cb79fSThomas Graf [XFRMA_SRCADDR] = { .len = sizeof(xfrm_address_t) }, 2392cf5cb79fSThomas Graf [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, 2393cf5cb79fSThomas Graf [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, 2394cf5cb79fSThomas Graf [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, 239513c1d189SArnaud Ebalard [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, 23966f26b61eSJamal Hadi Salim [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, 239735d2856bSMartin Willi [XFRMA_TFCPAD] = { .type = NLA_U32 }, 2398d8647b79SSteffen Klassert [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, 2399a947b0a9SNicolas Dichtel [XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 }, 2400d3623099SNicolas Dichtel [XFRMA_PROTO] = { .type = NLA_U8 }, 2401870a2df4SNicolas Dichtel [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, 2402cf5cb79fSThomas Graf }; 2403cf5cb79fSThomas Graf 2404880a6fabSChristophe Gouault static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { 2405880a6fabSChristophe Gouault [XFRMA_SPD_IPV4_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) }, 2406880a6fabSChristophe Gouault [XFRMA_SPD_IPV6_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) }, 2407880a6fabSChristophe Gouault }; 2408880a6fabSChristophe Gouault 240905600a79SMathias Krause static const struct xfrm_link { 24105424f32eSThomas Graf int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); 24111da177e4SLinus Torvalds int (*dump)(struct sk_buff *, struct netlink_callback *); 24124c563f76STimo Teras int (*done)(struct netlink_callback *); 2413880a6fabSChristophe Gouault const struct nla_policy *nla_pol; 2414880a6fabSChristophe Gouault int nla_max; 2415492b558bSThomas Graf } xfrm_dispatch[XFRM_NR_MSGTYPES] = { 2416492b558bSThomas Graf [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 2417492b558bSThomas Graf [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, 2418492b558bSThomas Graf [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, 24194c563f76STimo Teras .dump = xfrm_dump_sa, 24204c563f76STimo Teras .done = xfrm_dump_sa_done }, 2421492b558bSThomas Graf [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 2422492b558bSThomas Graf [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, 2423492b558bSThomas Graf [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, 24244c563f76STimo Teras .dump = xfrm_dump_policy, 24254c563f76STimo Teras .done = xfrm_dump_policy_done }, 2426492b558bSThomas Graf [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, 2427980ebd25SJamal Hadi Salim [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, 242853bc6b4dSJamal Hadi Salim [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, 2429492b558bSThomas Graf [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 2430492b558bSThomas Graf [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 24316c5c8ca7SJamal Hadi Salim [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, 2432492b558bSThomas Graf [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, 2433492b558bSThomas Graf [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, 2434d51d081dSJamal Hadi Salim [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, 2435d51d081dSJamal Hadi Salim [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, 24365c79de6eSShinta Sugimoto [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, 243728d8909bSJamal Hadi Salim [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo }, 2438880a6fabSChristophe Gouault [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_set_spdinfo, 2439880a6fabSChristophe Gouault .nla_pol = xfrma_spd_policy, 2440880a6fabSChristophe Gouault .nla_max = XFRMA_SPD_MAX }, 2441ecfd6b18SJamal Hadi Salim [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo }, 24421da177e4SLinus Torvalds }; 24431da177e4SLinus Torvalds 24441d00a4ebSThomas Graf static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 24451da177e4SLinus Torvalds { 2446a6483b79SAlexey Dobriyan struct net *net = sock_net(skb->sk); 244735a7aa08SThomas Graf struct nlattr *attrs[XFRMA_MAX+1]; 244805600a79SMathias Krause const struct xfrm_link *link; 2449a7bd9a45SThomas Graf int type, err; 24501da177e4SLinus Torvalds 245174005991SFan Du #ifdef CONFIG_COMPAT 24522bf8c476SAndy Lutomirski if (in_compat_syscall()) 245383e2d058SYi Zhao return -EOPNOTSUPP; 245474005991SFan Du #endif 245574005991SFan Du 24561da177e4SLinus Torvalds type = nlh->nlmsg_type; 24571da177e4SLinus Torvalds if (type > XFRM_MSG_MAX) 24581d00a4ebSThomas Graf return -EINVAL; 24591da177e4SLinus Torvalds 24601da177e4SLinus Torvalds type -= XFRM_MSG_BASE; 24611da177e4SLinus Torvalds link = &xfrm_dispatch[type]; 24621da177e4SLinus Torvalds 24631da177e4SLinus Torvalds /* All operations require privileges, even GET */ 246490f62cf3SEric W. Biederman if (!netlink_net_capable(skb, CAP_NET_ADMIN)) 24651d00a4ebSThomas Graf return -EPERM; 24661da177e4SLinus Torvalds 2467492b558bSThomas Graf if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || 2468492b558bSThomas Graf type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && 2469b8f3ab42SDavid S. Miller (nlh->nlmsg_flags & NLM_F_DUMP)) { 24701da177e4SLinus Torvalds if (link->dump == NULL) 24711d00a4ebSThomas Graf return -EINVAL; 24721da177e4SLinus Torvalds 247380d326faSPablo Neira Ayuso { 247480d326faSPablo Neira Ayuso struct netlink_dump_control c = { 247580d326faSPablo Neira Ayuso .dump = link->dump, 247680d326faSPablo Neira Ayuso .done = link->done, 247780d326faSPablo Neira Ayuso }; 247880d326faSPablo Neira Ayuso return netlink_dump_start(net->xfrm.nlsk, skb, nlh, &c); 247980d326faSPablo Neira Ayuso } 24801da177e4SLinus Torvalds } 24811da177e4SLinus Torvalds 2482880a6fabSChristophe Gouault err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, 2483880a6fabSChristophe Gouault link->nla_max ? : XFRMA_MAX, 2484880a6fabSChristophe Gouault link->nla_pol ? : xfrma_policy); 2485a7bd9a45SThomas Graf if (err < 0) 2486a7bd9a45SThomas Graf return err; 24871da177e4SLinus Torvalds 24881da177e4SLinus Torvalds if (link->doit == NULL) 24891d00a4ebSThomas Graf return -EINVAL; 24901da177e4SLinus Torvalds 24915424f32eSThomas Graf return link->doit(skb, nlh, attrs); 24921da177e4SLinus Torvalds } 24931da177e4SLinus Torvalds 2494cd40b7d3SDenis V. Lunev static void xfrm_netlink_rcv(struct sk_buff *skb) 24951da177e4SLinus Torvalds { 2496283bc9f3SFan Du struct net *net = sock_net(skb->sk); 2497283bc9f3SFan Du 2498283bc9f3SFan Du mutex_lock(&net->xfrm.xfrm_cfg_mutex); 2499cd40b7d3SDenis V. Lunev netlink_rcv_skb(skb, &xfrm_user_rcv_msg); 2500283bc9f3SFan Du mutex_unlock(&net->xfrm.xfrm_cfg_mutex); 25011da177e4SLinus Torvalds } 25021da177e4SLinus Torvalds 25037deb2264SThomas Graf static inline size_t xfrm_expire_msgsize(void) 25047deb2264SThomas Graf { 25056f26b61eSJamal Hadi Salim return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) 25066f26b61eSJamal Hadi Salim + nla_total_size(sizeof(struct xfrm_mark)); 25077deb2264SThomas Graf } 25087deb2264SThomas Graf 2509214e005bSDavid S. Miller static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c) 25101da177e4SLinus Torvalds { 25111da177e4SLinus Torvalds struct xfrm_user_expire *ue; 25121da177e4SLinus Torvalds struct nlmsghdr *nlh; 25131d1e34ddSDavid S. Miller int err; 25141da177e4SLinus Torvalds 251515e47304SEric W. Biederman nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0); 251679b8b7f4SThomas Graf if (nlh == NULL) 251779b8b7f4SThomas Graf return -EMSGSIZE; 25181da177e4SLinus Torvalds 25197b67c857SThomas Graf ue = nlmsg_data(nlh); 25201da177e4SLinus Torvalds copy_to_user_state(x, &ue->state); 2521d51d081dSJamal Hadi Salim ue->hard = (c->data.hard != 0) ? 1 : 0; 25221da177e4SLinus Torvalds 25231d1e34ddSDavid S. Miller err = xfrm_mark_put(skb, &x->mark); 25241d1e34ddSDavid S. Miller if (err) 25251d1e34ddSDavid S. Miller return err; 25266f26b61eSJamal Hadi Salim 2527053c095aSJohannes Berg nlmsg_end(skb, nlh); 2528053c095aSJohannes Berg return 0; 25291da177e4SLinus Torvalds } 25301da177e4SLinus Torvalds 2531214e005bSDavid S. Miller static int xfrm_exp_state_notify(struct xfrm_state *x, const struct km_event *c) 25321da177e4SLinus Torvalds { 2533fc34acd3SAlexey Dobriyan struct net *net = xs_net(x); 25341da177e4SLinus Torvalds struct sk_buff *skb; 25351da177e4SLinus Torvalds 25367deb2264SThomas Graf skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC); 25371da177e4SLinus Torvalds if (skb == NULL) 25381da177e4SLinus Torvalds return -ENOMEM; 25391da177e4SLinus Torvalds 25406f26b61eSJamal Hadi Salim if (build_expire(skb, x, c) < 0) { 25416f26b61eSJamal Hadi Salim kfree_skb(skb); 25426f26b61eSJamal Hadi Salim return -EMSGSIZE; 25436f26b61eSJamal Hadi Salim } 25441da177e4SLinus Torvalds 254521ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE); 25461da177e4SLinus Torvalds } 25471da177e4SLinus Torvalds 2548214e005bSDavid S. Miller static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event *c) 2549d51d081dSJamal Hadi Salim { 2550fc34acd3SAlexey Dobriyan struct net *net = xs_net(x); 2551d51d081dSJamal Hadi Salim struct sk_buff *skb; 2552d51d081dSJamal Hadi Salim 2553d8647b79SSteffen Klassert skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC); 2554d51d081dSJamal Hadi Salim if (skb == NULL) 2555d51d081dSJamal Hadi Salim return -ENOMEM; 2556d51d081dSJamal Hadi Salim 2557d51d081dSJamal Hadi Salim if (build_aevent(skb, x, c) < 0) 2558d51d081dSJamal Hadi Salim BUG(); 2559d51d081dSJamal Hadi Salim 256021ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_AEVENTS); 2561d51d081dSJamal Hadi Salim } 2562d51d081dSJamal Hadi Salim 2563214e005bSDavid S. Miller static int xfrm_notify_sa_flush(const struct km_event *c) 256426b15dadSJamal Hadi Salim { 25657067802eSAlexey Dobriyan struct net *net = c->net; 256626b15dadSJamal Hadi Salim struct xfrm_usersa_flush *p; 256726b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 256826b15dadSJamal Hadi Salim struct sk_buff *skb; 25697deb2264SThomas Graf int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush)); 257026b15dadSJamal Hadi Salim 25717deb2264SThomas Graf skb = nlmsg_new(len, GFP_ATOMIC); 257226b15dadSJamal Hadi Salim if (skb == NULL) 257326b15dadSJamal Hadi Salim return -ENOMEM; 257426b15dadSJamal Hadi Salim 257515e47304SEric W. Biederman nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0); 257679b8b7f4SThomas Graf if (nlh == NULL) { 257779b8b7f4SThomas Graf kfree_skb(skb); 257879b8b7f4SThomas Graf return -EMSGSIZE; 257979b8b7f4SThomas Graf } 258026b15dadSJamal Hadi Salim 25817b67c857SThomas Graf p = nlmsg_data(nlh); 2582bf08867fSHerbert Xu p->proto = c->data.proto; 258326b15dadSJamal Hadi Salim 25849825069dSThomas Graf nlmsg_end(skb, nlh); 258526b15dadSJamal Hadi Salim 258621ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA); 258726b15dadSJamal Hadi Salim } 258826b15dadSJamal Hadi Salim 25897deb2264SThomas Graf static inline size_t xfrm_sa_len(struct xfrm_state *x) 259026b15dadSJamal Hadi Salim { 25917deb2264SThomas Graf size_t l = 0; 25921a6509d9SHerbert Xu if (x->aead) 25931a6509d9SHerbert Xu l += nla_total_size(aead_len(x->aead)); 25944447bb33SMartin Willi if (x->aalg) { 25954447bb33SMartin Willi l += nla_total_size(sizeof(struct xfrm_algo) + 25964447bb33SMartin Willi (x->aalg->alg_key_len + 7) / 8); 25974447bb33SMartin Willi l += nla_total_size(xfrm_alg_auth_len(x->aalg)); 25984447bb33SMartin Willi } 259926b15dadSJamal Hadi Salim if (x->ealg) 26000f99be0dSEric Dumazet l += nla_total_size(xfrm_alg_len(x->ealg)); 260126b15dadSJamal Hadi Salim if (x->calg) 26027deb2264SThomas Graf l += nla_total_size(sizeof(*x->calg)); 260326b15dadSJamal Hadi Salim if (x->encap) 26047deb2264SThomas Graf l += nla_total_size(sizeof(*x->encap)); 260535d2856bSMartin Willi if (x->tfcpad) 260635d2856bSMartin Willi l += nla_total_size(sizeof(x->tfcpad)); 2607d8647b79SSteffen Klassert if (x->replay_esn) 2608d8647b79SSteffen Klassert l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn)); 2609f293a5e3Sdingzhi else 2610f293a5e3Sdingzhi l += nla_total_size(sizeof(struct xfrm_replay_state)); 261168325d3bSHerbert Xu if (x->security) 261268325d3bSHerbert Xu l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + 261368325d3bSHerbert Xu x->security->ctx_len); 261468325d3bSHerbert Xu if (x->coaddr) 261568325d3bSHerbert Xu l += nla_total_size(sizeof(*x->coaddr)); 2616a947b0a9SNicolas Dichtel if (x->props.extra_flags) 2617a947b0a9SNicolas Dichtel l += nla_total_size(sizeof(x->props.extra_flags)); 261868325d3bSHerbert Xu 2619d26f3984SHerbert Xu /* Must count x->lastused as it may become non-zero behind our back. */ 2620de95c4a4SNicolas Dichtel l += nla_total_size_64bit(sizeof(u64)); 262126b15dadSJamal Hadi Salim 262226b15dadSJamal Hadi Salim return l; 262326b15dadSJamal Hadi Salim } 262426b15dadSJamal Hadi Salim 2625214e005bSDavid S. Miller static int xfrm_notify_sa(struct xfrm_state *x, const struct km_event *c) 262626b15dadSJamal Hadi Salim { 2627fc34acd3SAlexey Dobriyan struct net *net = xs_net(x); 262826b15dadSJamal Hadi Salim struct xfrm_usersa_info *p; 26290603eac0SHerbert Xu struct xfrm_usersa_id *id; 263026b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 263126b15dadSJamal Hadi Salim struct sk_buff *skb; 263226b15dadSJamal Hadi Salim int len = xfrm_sa_len(x); 26331d1e34ddSDavid S. Miller int headlen, err; 26340603eac0SHerbert Xu 26350603eac0SHerbert Xu headlen = sizeof(*p); 26360603eac0SHerbert Xu if (c->event == XFRM_MSG_DELSA) { 26377deb2264SThomas Graf len += nla_total_size(headlen); 26380603eac0SHerbert Xu headlen = sizeof(*id); 26396f26b61eSJamal Hadi Salim len += nla_total_size(sizeof(struct xfrm_mark)); 26400603eac0SHerbert Xu } 26417deb2264SThomas Graf len += NLMSG_ALIGN(headlen); 264226b15dadSJamal Hadi Salim 26437deb2264SThomas Graf skb = nlmsg_new(len, GFP_ATOMIC); 264426b15dadSJamal Hadi Salim if (skb == NULL) 264526b15dadSJamal Hadi Salim return -ENOMEM; 264626b15dadSJamal Hadi Salim 264715e47304SEric W. Biederman nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0); 26481d1e34ddSDavid S. Miller err = -EMSGSIZE; 264979b8b7f4SThomas Graf if (nlh == NULL) 26501d1e34ddSDavid S. Miller goto out_free_skb; 265126b15dadSJamal Hadi Salim 26527b67c857SThomas Graf p = nlmsg_data(nlh); 26530603eac0SHerbert Xu if (c->event == XFRM_MSG_DELSA) { 2654c0144beaSThomas Graf struct nlattr *attr; 2655c0144beaSThomas Graf 26567b67c857SThomas Graf id = nlmsg_data(nlh); 26570603eac0SHerbert Xu memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); 26580603eac0SHerbert Xu id->spi = x->id.spi; 26590603eac0SHerbert Xu id->family = x->props.family; 26600603eac0SHerbert Xu id->proto = x->id.proto; 26610603eac0SHerbert Xu 2662c0144beaSThomas Graf attr = nla_reserve(skb, XFRMA_SA, sizeof(*p)); 26631d1e34ddSDavid S. Miller err = -EMSGSIZE; 2664c0144beaSThomas Graf if (attr == NULL) 26651d1e34ddSDavid S. Miller goto out_free_skb; 2666c0144beaSThomas Graf 2667c0144beaSThomas Graf p = nla_data(attr); 26680603eac0SHerbert Xu } 26691d1e34ddSDavid S. Miller err = copy_to_user_state_extra(x, p, skb); 26701d1e34ddSDavid S. Miller if (err) 26711d1e34ddSDavid S. Miller goto out_free_skb; 267226b15dadSJamal Hadi Salim 26739825069dSThomas Graf nlmsg_end(skb, nlh); 267426b15dadSJamal Hadi Salim 267521ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA); 267626b15dadSJamal Hadi Salim 26771d1e34ddSDavid S. Miller out_free_skb: 267826b15dadSJamal Hadi Salim kfree_skb(skb); 26791d1e34ddSDavid S. Miller return err; 268026b15dadSJamal Hadi Salim } 268126b15dadSJamal Hadi Salim 2682214e005bSDavid S. Miller static int xfrm_send_state_notify(struct xfrm_state *x, const struct km_event *c) 268326b15dadSJamal Hadi Salim { 268426b15dadSJamal Hadi Salim 268526b15dadSJamal Hadi Salim switch (c->event) { 2686f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 268726b15dadSJamal Hadi Salim return xfrm_exp_state_notify(x, c); 2688d51d081dSJamal Hadi Salim case XFRM_MSG_NEWAE: 2689d51d081dSJamal Hadi Salim return xfrm_aevent_state_notify(x, c); 2690f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 2691f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 2692f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 269326b15dadSJamal Hadi Salim return xfrm_notify_sa(x, c); 2694f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHSA: 269526b15dadSJamal Hadi Salim return xfrm_notify_sa_flush(c); 269626b15dadSJamal Hadi Salim default: 269762db5cfdSstephen hemminger printk(KERN_NOTICE "xfrm_user: Unknown SA event %d\n", 269862db5cfdSstephen hemminger c->event); 269926b15dadSJamal Hadi Salim break; 270026b15dadSJamal Hadi Salim } 270126b15dadSJamal Hadi Salim 270226b15dadSJamal Hadi Salim return 0; 270326b15dadSJamal Hadi Salim 270426b15dadSJamal Hadi Salim } 270526b15dadSJamal Hadi Salim 27067deb2264SThomas Graf static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x, 27077deb2264SThomas Graf struct xfrm_policy *xp) 27087deb2264SThomas Graf { 27097deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) 27107deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) 27116f26b61eSJamal Hadi Salim + nla_total_size(sizeof(struct xfrm_mark)) 27127deb2264SThomas Graf + nla_total_size(xfrm_user_sec_ctx_size(x->security)) 27137deb2264SThomas Graf + userpolicy_type_attrsize(); 27147deb2264SThomas Graf } 27157deb2264SThomas Graf 27161da177e4SLinus Torvalds static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, 271765e0736bSFan Du struct xfrm_tmpl *xt, struct xfrm_policy *xp) 27181da177e4SLinus Torvalds { 27191d1e34ddSDavid S. Miller __u32 seq = xfrm_get_acqseq(); 27201da177e4SLinus Torvalds struct xfrm_user_acquire *ua; 27211da177e4SLinus Torvalds struct nlmsghdr *nlh; 27221d1e34ddSDavid S. Miller int err; 27231da177e4SLinus Torvalds 272479b8b7f4SThomas Graf nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0); 272579b8b7f4SThomas Graf if (nlh == NULL) 272679b8b7f4SThomas Graf return -EMSGSIZE; 27271da177e4SLinus Torvalds 27287b67c857SThomas Graf ua = nlmsg_data(nlh); 27291da177e4SLinus Torvalds memcpy(&ua->id, &x->id, sizeof(ua->id)); 27301da177e4SLinus Torvalds memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); 27311da177e4SLinus Torvalds memcpy(&ua->sel, &x->sel, sizeof(ua->sel)); 273265e0736bSFan Du copy_to_user_policy(xp, &ua->policy, XFRM_POLICY_OUT); 27331da177e4SLinus Torvalds ua->aalgos = xt->aalgos; 27341da177e4SLinus Torvalds ua->ealgos = xt->ealgos; 27351da177e4SLinus Torvalds ua->calgos = xt->calgos; 27361da177e4SLinus Torvalds ua->seq = x->km.seq = seq; 27371da177e4SLinus Torvalds 27381d1e34ddSDavid S. Miller err = copy_to_user_tmpl(xp, skb); 27391d1e34ddSDavid S. Miller if (!err) 27401d1e34ddSDavid S. Miller err = copy_to_user_state_sec_ctx(x, skb); 27411d1e34ddSDavid S. Miller if (!err) 27421d1e34ddSDavid S. Miller err = copy_to_user_policy_type(xp->type, skb); 27431d1e34ddSDavid S. Miller if (!err) 27441d1e34ddSDavid S. Miller err = xfrm_mark_put(skb, &xp->mark); 27451d1e34ddSDavid S. Miller if (err) { 27461d1e34ddSDavid S. Miller nlmsg_cancel(skb, nlh); 27471d1e34ddSDavid S. Miller return err; 27481d1e34ddSDavid S. Miller } 27491da177e4SLinus Torvalds 2750053c095aSJohannes Berg nlmsg_end(skb, nlh); 2751053c095aSJohannes Berg return 0; 27521da177e4SLinus Torvalds } 27531da177e4SLinus Torvalds 27541da177e4SLinus Torvalds static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, 275565e0736bSFan Du struct xfrm_policy *xp) 27561da177e4SLinus Torvalds { 2757a6483b79SAlexey Dobriyan struct net *net = xs_net(x); 27581da177e4SLinus Torvalds struct sk_buff *skb; 27591da177e4SLinus Torvalds 27607deb2264SThomas Graf skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC); 27611da177e4SLinus Torvalds if (skb == NULL) 27621da177e4SLinus Torvalds return -ENOMEM; 27631da177e4SLinus Torvalds 276465e0736bSFan Du if (build_acquire(skb, x, xt, xp) < 0) 27651da177e4SLinus Torvalds BUG(); 27661da177e4SLinus Torvalds 276721ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE); 27681da177e4SLinus Torvalds } 27691da177e4SLinus Torvalds 27701da177e4SLinus Torvalds /* User gives us xfrm_user_policy_info followed by an array of 0 27711da177e4SLinus Torvalds * or more templates. 27721da177e4SLinus Torvalds */ 2773cb969f07SVenkat Yekkirala static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, 27741da177e4SLinus Torvalds u8 *data, int len, int *dir) 27751da177e4SLinus Torvalds { 2776fc34acd3SAlexey Dobriyan struct net *net = sock_net(sk); 27771da177e4SLinus Torvalds struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; 27781da177e4SLinus Torvalds struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1); 27791da177e4SLinus Torvalds struct xfrm_policy *xp; 27801da177e4SLinus Torvalds int nr; 27811da177e4SLinus Torvalds 2782cb969f07SVenkat Yekkirala switch (sk->sk_family) { 27831da177e4SLinus Torvalds case AF_INET: 27841da177e4SLinus Torvalds if (opt != IP_XFRM_POLICY) { 27851da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 27861da177e4SLinus Torvalds return NULL; 27871da177e4SLinus Torvalds } 27881da177e4SLinus Torvalds break; 2789dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 27901da177e4SLinus Torvalds case AF_INET6: 27911da177e4SLinus Torvalds if (opt != IPV6_XFRM_POLICY) { 27921da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 27931da177e4SLinus Torvalds return NULL; 27941da177e4SLinus Torvalds } 27951da177e4SLinus Torvalds break; 27961da177e4SLinus Torvalds #endif 27971da177e4SLinus Torvalds default: 27981da177e4SLinus Torvalds *dir = -EINVAL; 27991da177e4SLinus Torvalds return NULL; 28001da177e4SLinus Torvalds } 28011da177e4SLinus Torvalds 28021da177e4SLinus Torvalds *dir = -EINVAL; 28031da177e4SLinus Torvalds 28041da177e4SLinus Torvalds if (len < sizeof(*p) || 28051da177e4SLinus Torvalds verify_newpolicy_info(p)) 28061da177e4SLinus Torvalds return NULL; 28071da177e4SLinus Torvalds 28081da177e4SLinus Torvalds nr = ((len - sizeof(*p)) / sizeof(*ut)); 2809b4ad86bfSDavid S. Miller if (validate_tmpl(nr, ut, p->sel.family)) 28101da177e4SLinus Torvalds return NULL; 28111da177e4SLinus Torvalds 2812a4f1bac6SHerbert Xu if (p->dir > XFRM_POLICY_OUT) 2813a4f1bac6SHerbert Xu return NULL; 2814a4f1bac6SHerbert Xu 28152f09a4d5SHerbert Xu xp = xfrm_policy_alloc(net, GFP_ATOMIC); 28161da177e4SLinus Torvalds if (xp == NULL) { 28171da177e4SLinus Torvalds *dir = -ENOBUFS; 28181da177e4SLinus Torvalds return NULL; 28191da177e4SLinus Torvalds } 28201da177e4SLinus Torvalds 28211da177e4SLinus Torvalds copy_from_user_policy(xp, p); 2822f7b6983fSMasahide NAKAMURA xp->type = XFRM_POLICY_TYPE_MAIN; 28231da177e4SLinus Torvalds copy_templates(xp, ut, nr); 28241da177e4SLinus Torvalds 28251da177e4SLinus Torvalds *dir = p->dir; 28261da177e4SLinus Torvalds 28271da177e4SLinus Torvalds return xp; 28281da177e4SLinus Torvalds } 28291da177e4SLinus Torvalds 28307deb2264SThomas Graf static inline size_t xfrm_polexpire_msgsize(struct xfrm_policy *xp) 28317deb2264SThomas Graf { 28327deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) 28337deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) 28347deb2264SThomas Graf + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) 2835295fae56SJamal Hadi Salim + nla_total_size(sizeof(struct xfrm_mark)) 28367deb2264SThomas Graf + userpolicy_type_attrsize(); 28377deb2264SThomas Graf } 28387deb2264SThomas Graf 28391da177e4SLinus Torvalds static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, 2840214e005bSDavid S. Miller int dir, const struct km_event *c) 28411da177e4SLinus Torvalds { 28421da177e4SLinus Torvalds struct xfrm_user_polexpire *upe; 2843d51d081dSJamal Hadi Salim int hard = c->data.hard; 28441d1e34ddSDavid S. Miller struct nlmsghdr *nlh; 28451d1e34ddSDavid S. Miller int err; 28461da177e4SLinus Torvalds 284715e47304SEric W. Biederman nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0); 284879b8b7f4SThomas Graf if (nlh == NULL) 284979b8b7f4SThomas Graf return -EMSGSIZE; 28501da177e4SLinus Torvalds 28517b67c857SThomas Graf upe = nlmsg_data(nlh); 28521da177e4SLinus Torvalds copy_to_user_policy(xp, &upe->pol, dir); 28531d1e34ddSDavid S. Miller err = copy_to_user_tmpl(xp, skb); 28541d1e34ddSDavid S. Miller if (!err) 28551d1e34ddSDavid S. Miller err = copy_to_user_sec_ctx(xp, skb); 28561d1e34ddSDavid S. Miller if (!err) 28571d1e34ddSDavid S. Miller err = copy_to_user_policy_type(xp->type, skb); 28581d1e34ddSDavid S. Miller if (!err) 28591d1e34ddSDavid S. Miller err = xfrm_mark_put(skb, &xp->mark); 28601d1e34ddSDavid S. Miller if (err) { 28611d1e34ddSDavid S. Miller nlmsg_cancel(skb, nlh); 28621d1e34ddSDavid S. Miller return err; 28631d1e34ddSDavid S. Miller } 28641da177e4SLinus Torvalds upe->hard = !!hard; 28651da177e4SLinus Torvalds 2866053c095aSJohannes Berg nlmsg_end(skb, nlh); 2867053c095aSJohannes Berg return 0; 28681da177e4SLinus Torvalds } 28691da177e4SLinus Torvalds 2870214e005bSDavid S. Miller static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 28711da177e4SLinus Torvalds { 2872fc34acd3SAlexey Dobriyan struct net *net = xp_net(xp); 28731da177e4SLinus Torvalds struct sk_buff *skb; 28741da177e4SLinus Torvalds 28757deb2264SThomas Graf skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC); 28761da177e4SLinus Torvalds if (skb == NULL) 28771da177e4SLinus Torvalds return -ENOMEM; 28781da177e4SLinus Torvalds 2879d51d081dSJamal Hadi Salim if (build_polexpire(skb, xp, dir, c) < 0) 28801da177e4SLinus Torvalds BUG(); 28811da177e4SLinus Torvalds 288221ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE); 28831da177e4SLinus Torvalds } 28841da177e4SLinus Torvalds 2885214e005bSDavid S. Miller static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c) 288626b15dadSJamal Hadi Salim { 28871d1e34ddSDavid S. Miller int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 2888fc34acd3SAlexey Dobriyan struct net *net = xp_net(xp); 288926b15dadSJamal Hadi Salim struct xfrm_userpolicy_info *p; 28900603eac0SHerbert Xu struct xfrm_userpolicy_id *id; 289126b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 289226b15dadSJamal Hadi Salim struct sk_buff *skb; 28931d1e34ddSDavid S. Miller int headlen, err; 28940603eac0SHerbert Xu 28950603eac0SHerbert Xu headlen = sizeof(*p); 28960603eac0SHerbert Xu if (c->event == XFRM_MSG_DELPOLICY) { 28977deb2264SThomas Graf len += nla_total_size(headlen); 28980603eac0SHerbert Xu headlen = sizeof(*id); 28990603eac0SHerbert Xu } 2900cfbfd45aSThomas Graf len += userpolicy_type_attrsize(); 2901295fae56SJamal Hadi Salim len += nla_total_size(sizeof(struct xfrm_mark)); 29027deb2264SThomas Graf len += NLMSG_ALIGN(headlen); 290326b15dadSJamal Hadi Salim 29047deb2264SThomas Graf skb = nlmsg_new(len, GFP_ATOMIC); 290526b15dadSJamal Hadi Salim if (skb == NULL) 290626b15dadSJamal Hadi Salim return -ENOMEM; 290726b15dadSJamal Hadi Salim 290815e47304SEric W. Biederman nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0); 29091d1e34ddSDavid S. Miller err = -EMSGSIZE; 291079b8b7f4SThomas Graf if (nlh == NULL) 29111d1e34ddSDavid S. Miller goto out_free_skb; 291226b15dadSJamal Hadi Salim 29137b67c857SThomas Graf p = nlmsg_data(nlh); 29140603eac0SHerbert Xu if (c->event == XFRM_MSG_DELPOLICY) { 2915c0144beaSThomas Graf struct nlattr *attr; 2916c0144beaSThomas Graf 29177b67c857SThomas Graf id = nlmsg_data(nlh); 29180603eac0SHerbert Xu memset(id, 0, sizeof(*id)); 29190603eac0SHerbert Xu id->dir = dir; 29200603eac0SHerbert Xu if (c->data.byid) 29210603eac0SHerbert Xu id->index = xp->index; 29220603eac0SHerbert Xu else 29230603eac0SHerbert Xu memcpy(&id->sel, &xp->selector, sizeof(id->sel)); 29240603eac0SHerbert Xu 2925c0144beaSThomas Graf attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p)); 29261d1e34ddSDavid S. Miller err = -EMSGSIZE; 2927c0144beaSThomas Graf if (attr == NULL) 29281d1e34ddSDavid S. Miller goto out_free_skb; 2929c0144beaSThomas Graf 2930c0144beaSThomas Graf p = nla_data(attr); 29310603eac0SHerbert Xu } 293226b15dadSJamal Hadi Salim 293326b15dadSJamal Hadi Salim copy_to_user_policy(xp, p, dir); 29341d1e34ddSDavid S. Miller err = copy_to_user_tmpl(xp, skb); 29351d1e34ddSDavid S. Miller if (!err) 29361d1e34ddSDavid S. Miller err = copy_to_user_policy_type(xp->type, skb); 29371d1e34ddSDavid S. Miller if (!err) 29381d1e34ddSDavid S. Miller err = xfrm_mark_put(skb, &xp->mark); 29391d1e34ddSDavid S. Miller if (err) 29401d1e34ddSDavid S. Miller goto out_free_skb; 2941295fae56SJamal Hadi Salim 29429825069dSThomas Graf nlmsg_end(skb, nlh); 294326b15dadSJamal Hadi Salim 294421ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY); 294526b15dadSJamal Hadi Salim 29461d1e34ddSDavid S. Miller out_free_skb: 294726b15dadSJamal Hadi Salim kfree_skb(skb); 29481d1e34ddSDavid S. Miller return err; 294926b15dadSJamal Hadi Salim } 295026b15dadSJamal Hadi Salim 2951214e005bSDavid S. Miller static int xfrm_notify_policy_flush(const struct km_event *c) 295226b15dadSJamal Hadi Salim { 29537067802eSAlexey Dobriyan struct net *net = c->net; 295426b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 295526b15dadSJamal Hadi Salim struct sk_buff *skb; 29561d1e34ddSDavid S. Miller int err; 295726b15dadSJamal Hadi Salim 29587deb2264SThomas Graf skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC); 295926b15dadSJamal Hadi Salim if (skb == NULL) 296026b15dadSJamal Hadi Salim return -ENOMEM; 296126b15dadSJamal Hadi Salim 296215e47304SEric W. Biederman nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0); 29631d1e34ddSDavid S. Miller err = -EMSGSIZE; 296479b8b7f4SThomas Graf if (nlh == NULL) 29651d1e34ddSDavid S. Miller goto out_free_skb; 29661d1e34ddSDavid S. Miller err = copy_to_user_policy_type(c->data.type, skb); 29671d1e34ddSDavid S. Miller if (err) 29681d1e34ddSDavid S. Miller goto out_free_skb; 296926b15dadSJamal Hadi Salim 29709825069dSThomas Graf nlmsg_end(skb, nlh); 297126b15dadSJamal Hadi Salim 297221ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY); 297326b15dadSJamal Hadi Salim 29741d1e34ddSDavid S. Miller out_free_skb: 297526b15dadSJamal Hadi Salim kfree_skb(skb); 29761d1e34ddSDavid S. Miller return err; 297726b15dadSJamal Hadi Salim } 297826b15dadSJamal Hadi Salim 2979214e005bSDavid S. Miller static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 298026b15dadSJamal Hadi Salim { 298126b15dadSJamal Hadi Salim 298226b15dadSJamal Hadi Salim switch (c->event) { 2983f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 2984f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 2985f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 298626b15dadSJamal Hadi Salim return xfrm_notify_policy(xp, dir, c); 2987f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHPOLICY: 298826b15dadSJamal Hadi Salim return xfrm_notify_policy_flush(c); 2989f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 299026b15dadSJamal Hadi Salim return xfrm_exp_policy_notify(xp, dir, c); 299126b15dadSJamal Hadi Salim default: 299262db5cfdSstephen hemminger printk(KERN_NOTICE "xfrm_user: Unknown Policy event %d\n", 299362db5cfdSstephen hemminger c->event); 299426b15dadSJamal Hadi Salim } 299526b15dadSJamal Hadi Salim 299626b15dadSJamal Hadi Salim return 0; 299726b15dadSJamal Hadi Salim 299826b15dadSJamal Hadi Salim } 299926b15dadSJamal Hadi Salim 30007deb2264SThomas Graf static inline size_t xfrm_report_msgsize(void) 30017deb2264SThomas Graf { 30027deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_user_report)); 30037deb2264SThomas Graf } 30047deb2264SThomas Graf 300597a64b45SMasahide NAKAMURA static int build_report(struct sk_buff *skb, u8 proto, 300697a64b45SMasahide NAKAMURA struct xfrm_selector *sel, xfrm_address_t *addr) 300797a64b45SMasahide NAKAMURA { 300897a64b45SMasahide NAKAMURA struct xfrm_user_report *ur; 300997a64b45SMasahide NAKAMURA struct nlmsghdr *nlh; 301097a64b45SMasahide NAKAMURA 301179b8b7f4SThomas Graf nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0); 301279b8b7f4SThomas Graf if (nlh == NULL) 301379b8b7f4SThomas Graf return -EMSGSIZE; 301497a64b45SMasahide NAKAMURA 30157b67c857SThomas Graf ur = nlmsg_data(nlh); 301697a64b45SMasahide NAKAMURA ur->proto = proto; 301797a64b45SMasahide NAKAMURA memcpy(&ur->sel, sel, sizeof(ur->sel)); 301897a64b45SMasahide NAKAMURA 30191d1e34ddSDavid S. Miller if (addr) { 30201d1e34ddSDavid S. Miller int err = nla_put(skb, XFRMA_COADDR, sizeof(*addr), addr); 30211d1e34ddSDavid S. Miller if (err) { 30229825069dSThomas Graf nlmsg_cancel(skb, nlh); 30231d1e34ddSDavid S. Miller return err; 30241d1e34ddSDavid S. Miller } 30251d1e34ddSDavid S. Miller } 3026053c095aSJohannes Berg nlmsg_end(skb, nlh); 3027053c095aSJohannes Berg return 0; 302897a64b45SMasahide NAKAMURA } 302997a64b45SMasahide NAKAMURA 3030db983c11SAlexey Dobriyan static int xfrm_send_report(struct net *net, u8 proto, 3031db983c11SAlexey Dobriyan struct xfrm_selector *sel, xfrm_address_t *addr) 303297a64b45SMasahide NAKAMURA { 303397a64b45SMasahide NAKAMURA struct sk_buff *skb; 303497a64b45SMasahide NAKAMURA 30357deb2264SThomas Graf skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC); 303697a64b45SMasahide NAKAMURA if (skb == NULL) 303797a64b45SMasahide NAKAMURA return -ENOMEM; 303897a64b45SMasahide NAKAMURA 303997a64b45SMasahide NAKAMURA if (build_report(skb, proto, sel, addr) < 0) 304097a64b45SMasahide NAKAMURA BUG(); 304197a64b45SMasahide NAKAMURA 304221ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_REPORT); 304397a64b45SMasahide NAKAMURA } 304497a64b45SMasahide NAKAMURA 30453a2dfbe8SMartin Willi static inline size_t xfrm_mapping_msgsize(void) 30463a2dfbe8SMartin Willi { 30473a2dfbe8SMartin Willi return NLMSG_ALIGN(sizeof(struct xfrm_user_mapping)); 30483a2dfbe8SMartin Willi } 30493a2dfbe8SMartin Willi 30503a2dfbe8SMartin Willi static int build_mapping(struct sk_buff *skb, struct xfrm_state *x, 30513a2dfbe8SMartin Willi xfrm_address_t *new_saddr, __be16 new_sport) 30523a2dfbe8SMartin Willi { 30533a2dfbe8SMartin Willi struct xfrm_user_mapping *um; 30543a2dfbe8SMartin Willi struct nlmsghdr *nlh; 30553a2dfbe8SMartin Willi 30563a2dfbe8SMartin Willi nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MAPPING, sizeof(*um), 0); 30573a2dfbe8SMartin Willi if (nlh == NULL) 30583a2dfbe8SMartin Willi return -EMSGSIZE; 30593a2dfbe8SMartin Willi 30603a2dfbe8SMartin Willi um = nlmsg_data(nlh); 30613a2dfbe8SMartin Willi 30623a2dfbe8SMartin Willi memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr)); 30633a2dfbe8SMartin Willi um->id.spi = x->id.spi; 30643a2dfbe8SMartin Willi um->id.family = x->props.family; 30653a2dfbe8SMartin Willi um->id.proto = x->id.proto; 30663a2dfbe8SMartin Willi memcpy(&um->new_saddr, new_saddr, sizeof(um->new_saddr)); 30673a2dfbe8SMartin Willi memcpy(&um->old_saddr, &x->props.saddr, sizeof(um->old_saddr)); 30683a2dfbe8SMartin Willi um->new_sport = new_sport; 30693a2dfbe8SMartin Willi um->old_sport = x->encap->encap_sport; 30703a2dfbe8SMartin Willi um->reqid = x->props.reqid; 30713a2dfbe8SMartin Willi 3072053c095aSJohannes Berg nlmsg_end(skb, nlh); 3073053c095aSJohannes Berg return 0; 30743a2dfbe8SMartin Willi } 30753a2dfbe8SMartin Willi 30763a2dfbe8SMartin Willi static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, 30773a2dfbe8SMartin Willi __be16 sport) 30783a2dfbe8SMartin Willi { 3079a6483b79SAlexey Dobriyan struct net *net = xs_net(x); 30803a2dfbe8SMartin Willi struct sk_buff *skb; 30813a2dfbe8SMartin Willi 30823a2dfbe8SMartin Willi if (x->id.proto != IPPROTO_ESP) 30833a2dfbe8SMartin Willi return -EINVAL; 30843a2dfbe8SMartin Willi 30853a2dfbe8SMartin Willi if (!x->encap) 30863a2dfbe8SMartin Willi return -EINVAL; 30873a2dfbe8SMartin Willi 30883a2dfbe8SMartin Willi skb = nlmsg_new(xfrm_mapping_msgsize(), GFP_ATOMIC); 30893a2dfbe8SMartin Willi if (skb == NULL) 30903a2dfbe8SMartin Willi return -ENOMEM; 30913a2dfbe8SMartin Willi 30923a2dfbe8SMartin Willi if (build_mapping(skb, x, ipaddr, sport) < 0) 30933a2dfbe8SMartin Willi BUG(); 30943a2dfbe8SMartin Willi 309521ee543eSMichal Kubecek return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MAPPING); 30963a2dfbe8SMartin Willi } 30973a2dfbe8SMartin Willi 30980f24558eSHoria Geanta static bool xfrm_is_alive(const struct km_event *c) 30990f24558eSHoria Geanta { 31000f24558eSHoria Geanta return (bool)xfrm_acquire_is_on(c->net); 31010f24558eSHoria Geanta } 31020f24558eSHoria Geanta 31031da177e4SLinus Torvalds static struct xfrm_mgr netlink_mgr = { 31041da177e4SLinus Torvalds .id = "netlink", 31051da177e4SLinus Torvalds .notify = xfrm_send_state_notify, 31061da177e4SLinus Torvalds .acquire = xfrm_send_acquire, 31071da177e4SLinus Torvalds .compile_policy = xfrm_compile_policy, 31081da177e4SLinus Torvalds .notify_policy = xfrm_send_policy_notify, 310997a64b45SMasahide NAKAMURA .report = xfrm_send_report, 31105c79de6eSShinta Sugimoto .migrate = xfrm_send_migrate, 31113a2dfbe8SMartin Willi .new_mapping = xfrm_send_mapping, 31120f24558eSHoria Geanta .is_alive = xfrm_is_alive, 31131da177e4SLinus Torvalds }; 31141da177e4SLinus Torvalds 3115a6483b79SAlexey Dobriyan static int __net_init xfrm_user_net_init(struct net *net) 31161da177e4SLinus Torvalds { 3117be33690dSPatrick McHardy struct sock *nlsk; 3118a31f2d17SPablo Neira Ayuso struct netlink_kernel_cfg cfg = { 3119a31f2d17SPablo Neira Ayuso .groups = XFRMNLGRP_MAX, 3120a31f2d17SPablo Neira Ayuso .input = xfrm_netlink_rcv, 3121a31f2d17SPablo Neira Ayuso }; 3122be33690dSPatrick McHardy 31239f00d977SPablo Neira Ayuso nlsk = netlink_kernel_create(net, NETLINK_XFRM, &cfg); 3124be33690dSPatrick McHardy if (nlsk == NULL) 31251da177e4SLinus Torvalds return -ENOMEM; 3126d79d792eSEric W. Biederman net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */ 3127cf778b00SEric Dumazet rcu_assign_pointer(net->xfrm.nlsk, nlsk); 31281da177e4SLinus Torvalds return 0; 31291da177e4SLinus Torvalds } 31301da177e4SLinus Torvalds 3131d79d792eSEric W. Biederman static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list) 3132a6483b79SAlexey Dobriyan { 3133d79d792eSEric W. Biederman struct net *net; 3134d79d792eSEric W. Biederman list_for_each_entry(net, net_exit_list, exit_list) 3135a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(net->xfrm.nlsk, NULL); 3136d79d792eSEric W. Biederman synchronize_net(); 3137d79d792eSEric W. Biederman list_for_each_entry(net, net_exit_list, exit_list) 3138d79d792eSEric W. Biederman netlink_kernel_release(net->xfrm.nlsk_stash); 3139a6483b79SAlexey Dobriyan } 3140a6483b79SAlexey Dobriyan 3141a6483b79SAlexey Dobriyan static struct pernet_operations xfrm_user_net_ops = { 3142a6483b79SAlexey Dobriyan .init = xfrm_user_net_init, 3143d79d792eSEric W. Biederman .exit_batch = xfrm_user_net_exit, 3144a6483b79SAlexey Dobriyan }; 3145a6483b79SAlexey Dobriyan 3146a6483b79SAlexey Dobriyan static int __init xfrm_user_init(void) 3147a6483b79SAlexey Dobriyan { 3148a6483b79SAlexey Dobriyan int rv; 3149a6483b79SAlexey Dobriyan 3150a6483b79SAlexey Dobriyan printk(KERN_INFO "Initializing XFRM netlink socket\n"); 3151a6483b79SAlexey Dobriyan 3152a6483b79SAlexey Dobriyan rv = register_pernet_subsys(&xfrm_user_net_ops); 3153a6483b79SAlexey Dobriyan if (rv < 0) 3154a6483b79SAlexey Dobriyan return rv; 3155a6483b79SAlexey Dobriyan rv = xfrm_register_km(&netlink_mgr); 3156a6483b79SAlexey Dobriyan if (rv < 0) 3157a6483b79SAlexey Dobriyan unregister_pernet_subsys(&xfrm_user_net_ops); 3158a6483b79SAlexey Dobriyan return rv; 3159a6483b79SAlexey Dobriyan } 3160a6483b79SAlexey Dobriyan 31611da177e4SLinus Torvalds static void __exit xfrm_user_exit(void) 31621da177e4SLinus Torvalds { 31631da177e4SLinus Torvalds xfrm_unregister_km(&netlink_mgr); 3164a6483b79SAlexey Dobriyan unregister_pernet_subsys(&xfrm_user_net_ops); 31651da177e4SLinus Torvalds } 31661da177e4SLinus Torvalds 31671da177e4SLinus Torvalds module_init(xfrm_user_init); 31681da177e4SLinus Torvalds module_exit(xfrm_user_exit); 31691da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 31704fdb3bb7SHarald Welte MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); 3171f8cd5488SJamal Hadi Salim 3172